1
votes

Le module Branca Python est incapable de trouver 2 fichiers json essentiels lors de l'exécution d'un exécutable qui utilise folium

Il y a une chance que ce soit encore un problème et que les gens de Pyinstaller et / ou Folium n'aient aucun intérêt à le réparer, mais je le posterai à nouveau ici au cas où quelqu'un trouverait une solution de contournement.

J'ai un programme qui crée des cartes, des géocodes, etc. et a récemment ajouté le package folium pour créer des cartes interactives au format html. Je compile toujours mon code à l'aide de pyinstaller afin que les autres membres de mon entreprise puissent simplement utiliser l'exécutable plutôt que d'exécuter le code python. Si j'exécute mon code dans un IDE, il se charge, s'exécute et fonctionne exactement comme prévu. Cependant, lorsque j'essaie de compiler alors que j'ai import folium quelque part dans mon script, j'obtiens une erreur en essayant d'exécuter l'exécutable créé par pyinstaller.

Le texte d'erreur lit quelque chose comme ceci:

resource_package = __name__
resource_path_schemes = '/_schemes.json'
resource_path_cnames = '/_cnames.json'

Je suis encore relativement nouveau dans Python, donc essayer de déchiffrer le problème avec ce texte est assez écrasant. Je n'ai aucune idée s'il existe une solution de contournement, où je dois juste éditer un fichier, ajouter un fichier ou ajouter un paramètre à pyinstaller, mais peut-être que quelqu'un d'autre peut le lire et avoir une idée de ce qui pourrait causer ce problème. Merci d'avance à tous ceux qui ont des suggestions.

EDIT: Le problème semble être avec branca, qui est une dépendance de folium. Il recherche ce fichier _cnames.json qui se trouve dans le dossier site-packages \ branca mais soit n'est pas copié comme il se doit, soit j'ai besoin d'identifier d'une manière ou d'une autre dans mon script où il doit rechercher ces fichiers, puis simplement copier manuellement les dans un dossier que je choisis.

MISE À JOUR SUPPLÉMENTAIRE: J'ai testé et testé et j'ai déterminé le cœur du problème. Lorsque vous exécutez votre exe, il est décompressé dans un dossier temporaire. L'un des modules de branca est colormap.py Dans le fichier colormap , il y a essentiellement trois lignes qui conservent branca code > de charger correctement.

Traceback (most recent call last):
File "analysisSuite.py", line 58, in <module>
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\folium\__init__.py", line 8, in <module>
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\branca\__init__.py", line 5, in <module>
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\branca\colormap.py", line 29, in <module>
File "site-packages\pkg_resources\__init__.py", line 1143, in resource_stream
File "site-packages\pkg_resources\__init__.py", line 1390, in get_resource_stream
File "site-packages\pkg_resources\__init__.py", line 1393, in get_resource_string
File "site-packages\pkg_resources\__init__.py", line 1469, in _get
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 479, in get_data
with open(path, 'rb') as fp:
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\natha\\AppData\\Local\\Temp\\_MEI309082\\branca\\_cnames.json'
[30956] Failed to execute script analysisSuite

Ainsi, lorsque l'exécutable est décompressé dans ce dossier temporaire et que branca essaie de se charger, à cause de ces lignes ci-dessus, il s'attend à ce que ces deux fichiers soient également dans cette temp dossier, mais bien sûr, ils ne le seront pas car on leur dit de toujours et uniquement d'être dans le dossier où se trouve le module de palette de couleurs. La clé ici est de trouver un moyen pour que la référence du chemin puisse être relative, afin qu'elle ne regarde pas dans le dossier temporaire mais aussi que la référence soit dynamique, de sorte que partout où vous avez votre exécutable, tant que vous les avez json présents dans un dossier dont il "connaît", alors vous serez bien. Maintenant, j'ai juste besoin de savoir comment faire cela.


0 commentaires

3 Réponses :


0
votes

Je n'ai pas pu faire fonctionner cela avec pyinstaller. J'ai dû utiliser à la place cx_Freeze.

pip install cx_Freeze

cx_Freeze nécessite qu'un fichier setup.py soit créé, généralement dans le même dossier que le script principal qui est converti en un exe. Mon fichier setup.py ressemble à ceci:

import sys
from cx_Freeze import setup, Executable
import os.path
PYTHON_INSTALL_DIR = os.path.dirname(os.path.dirname(os.__file__))
os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6')
os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6')

# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {"packages": ["pkg_resources","asyncio","os","pandas","numpy","idna","folium","branca","jinja2","matplotlib"]}

# GUI applications require a different base on Windows (the default is for a
# console application).
base = None
if sys.platform == "win32":
    base = "Win32GUI"

options = {
    'build_exe': {
        'include_files':[
            os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tk86t.dll'),
            os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tcl86t.dll'),
            # 'C:\\Users\\natha\\AppData\\Local\\Programs\\Python\\Python36-32\\Lib\\site-packages\\branca\\_cnames.json',
            # 'C:\\Users\\natha\\AppData\\Local\\Programs\\Python\\Python36-32\\Lib\\site-packages\\branca\\_schemes.json'
         ],
    },
}

setup(  name = "MyProgram",
        version = "0.1",
        description = "MyProgram that I created",
        options = {"build_exe": build_exe_options},
        executables = [Executable("myProgram.py", base=base)])

Remarquez que j'ai dû ajouter diverses dépendances folium au dictionnaire "packages", telles que branca, asyncio et pkg_resources. De plus, j'ai fait des mises à jour indépendantes pour asyncio, pkg_resources et même setuptools en utilisant pip - par exemple: pip install --upgrade setuptools

Une fois ceux-ci en place, j'ouvrirais une invite de commande à partir du répertoire où mon fichier setup.py est enregistré et tapez simplement python setup.py build Une fois que cela fonctionne, j'ai un nouveau dossier dans mon répertoire appelé build et à l'intérieur de celui-ci se trouve un autre dossier, à l'intérieur duquel se trouve mon exe, qui fonctionnait parfaitement. J'espère que cela aidera quelqu'un d'autre qui pourrait rencontrer ce problème.


0 commentaires

4
votes

J'ai eu le même problème. Pyinstaller n'a pas pu fonctionner avec le package Python Folium. Je n'ai pas pu faire fonctionner votre solution cx_Freeze en raison de problèmes avec Python 3.7 et cx_Freeze mais avec un jour de stress j'ai trouvé une solution Pyinstaller que je partage avec la communauté.

Tout d'abord, vous devez éditer ces 3 fichiers:

  1. \ folium \ folium.py

  2. \ folium \ raster_layers.py

  3. \ branca \ element.py

Apporte les modifications suivantes, en commentant la ligne ENV existante et en la remplaçant par le code ci-dessous:

pyinstaller time_punch_map.spec

Créez ce fichier de spécification dans votre dossier racine, évidemment votre chemin et le nom du projet seront différents:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['time_punch_map.py'],
         pathex=['C:\\Users\\XXXX\\PycharmProjects\\TimePunchMap'],
         binaries=[],
         datas=[
         (".\\venv\\Lib\\site-packages\\branca\\*.json","branca"),
         (".\\venv\\Lib\\site-packages\\branca\\templates","templates"),
         (".\\venv\\Lib\\site-packages\\folium\\templates","templates"),
         ],
         hiddenimports=[],
         hookspath=[],
         runtime_hooks=[],
         excludes=[],
         win_no_prefer_redirects=False,
         win_private_assemblies=False,
         cipher=block_cipher,
         noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
         cipher=block_cipher)
exe = EXE(pyz,
      a.scripts,
      a.binaries,
      a.zipfiles,
      a.datas,
      [],
      name='time_punch_map',
      debug=False,
      bootloader_ignore_signals=False,
      strip=False,
      upx=True,
      runtime_tmpdir=None,
      console=True )

Enfin, générez l'exe unique avec cette commande depuis le terminal:

#ENV = Environment(loader=PackageLoader('folium', 'templates'))
import os, sys
from jinja2 import FileSystemLoader
if getattr(sys, 'frozen', False):
        # we are running in a bundle
    templatedir = sys._MEIPASS
else:
    # we are running in a normal Python environment
    templatedir = os.path.dirname(os.path.abspath(__file__))
ENV = Environment(loader=FileSystemLoader(templatedir + '\\templates'))

p>


2 commentaires

Cela a tout à fait du sens et j'ai l'impression que c'est proche, mais après sa construction, lorsque j'exécute l'exécutable, j'obtiens toujours la partie supérieure de l'erreur - liée à \ PyInstaller \ loader \ pyimod03_importers.py


Le problème de mise en œuvre que j'ai rencontré était dû à ma propre ignorance. @chinguetti votre méthode résout mes problèmes exécutables.



0
votes

Avec pyinstaller, cela fonctionne en utilisant l'astuce ci-dessus. Si nous devons créer un dossier, ce fichier de script peut être utilisé.

import platform
block_cipher = None
a = Analysis(['Test_Beta.py'],
pathex=['C:\\Old desktop\\test\\esky\\fileserver\\test11'],
binaries=[(winsparkle, '.')],
datas=[
         ("C:\\Users\\kv\\AppData\\Local\\Continuum\\Anaconda3\\Lib\\site-packages\\branca\\*.json","branca"),
         ("C:\\Users\\kv\\AppData\\Local\\Continuum\\Anaconda3\\Lib\\site-packages\\branca\\templates","templates"),
         ("C:\\Users\\kv\\AppData\\Local\\Continuum\\Anaconda3\\Lib\\site-packages\\folium\\templates","templates"),
         ],
         hiddenimports=[],
         hookspath=[],
         runtime_hooks=[],
         excludes=['scipy', 'zmq', '_gtkagg', '_tkagg', 'bsddb', 'curses', 'pywin.debugger', 'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl', 'Tkconstants', 'Tkinter'],
         win_no_prefer_redirects=False,
         win_private_assemblies=False,
         cipher=block_cipher)
         
pyz = PYZ(a.pure, a.zipped_data,cipher=block_cipher)
exe = EXE( pyz,
      a.scripts,
      [],
      exclude_binaries=True,
      name='Outview',
      debug=False,
      strip=False,
      upx=True,
      console=False )

coll = COLLECT(exe,
           a.binaries,
           a.zipfiles,
           a.datas,
           strip=False,
           upx=True,
           name='Outview')    
    


0 commentaires