Évitez l'erreur d'exécution "KeyError: '_ max_key_len_'" pour les binaires générés par PyInstaller pour le code Python à l'aide de pykakasi

Contenu de l'article

Pour le code Python utilisant pykakasi, lorsque j'ai exécuté le fichier exécutable généré par PyInstaller, j'ai eu l'erreur "KeyError: '_ max_key_len_'". Notez comment l'éviter. J'utilise Linux (Ubuntu 18.04), python 3.7.5 et utilise pipenv.

Exemple de code

Code de cet article a été modifié et utilisé. J'utiliserai les 3 fichiers suivants pour démarrer la version binaire de foo.py.

foo.py



from mymod1 import bar
from mymod2 import hoge

bar("Hello!")
hoge("Hoge!")

mymod1.py



def bar(s):
    print(f"bar: {s}")

mymod2.py



import pykakasi

def hoge(s):
    kakasi = pykakasi.kakasi()

    kakasi.setMode('H', 'a')
    kakasi.setMode('K', 'a')
    kakasi.setMode('J', 'a')

    conv = kakasi.getConverter()
    print(conv.do(s))

Étapes pour obtenir une erreur d'exécution

Installez le module en procédant comme suit sur votre terminal:


pipenv install setuptools pykakasi pyinstaller

Les fichiers qui existent à ce stade sont les suivants.


$ ls
Pipfile
foo.py
mymod1.py
mymod2.py

Le Pipfile généré est le suivant.


[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
setuptools = "*"
pykakasi = "*"
pyinstaller = "*"

[requires]
python_version = "3.7"

Exécutez ce qui suit sur le terminal pour créer un fichier exécutable.


pipenv run pyinstaller foo.py

Si vous vérifiez le fichier avec ls, le répertoire de construction et le répertoire dist sont générés.


$ ls
Pipfile
build
dist
foo.py
foo.spec
mymod1.py
mymod2.py

Puisque "dist / foo / foo" est le fichier exécutable, lorsque j'ai essayé de le déplacer, "KeyError: '_ max_key_len_'" s'est produit comme indiqué ci-dessous.


$ dist/foo/foo 
bar: Hello!
Traceback (most recent call last):
  File "foo.py", line 5, in <module>
    hoge("Hoge!")
  File "mymod2.py", line 10, in hoge
    conv = kakasi.getConverter()
  File "pykakasi/kakasi.py", line 91, in getConverter
  File "pykakasi/kanji.py", line 30, in __init__
  File "pykakasi/kanji.py", line 126, in __init__
KeyError: '_max_key_len_'
[6202] Failed to execute script foo

Éviter les erreurs d'exécution

La cause était que le dictionnaire de pykakashi sous dist était insuffisant. Sous dist, il y a un dictionnaire comme indiqué ci-dessous.


$ ls dist/foo/pykakasi/data/
itaijidict3.db

D'autre part, il y avait 8 dictionnaires dans la destination d'installation par pipenv.


$ ls `pipenv --venv`/lib/python3.7/site-packages/pykakasi/data/
hepburndict3.db
itaijidict3.db
kunreidict3.db
passportdict3.db
hepburnhira3.db
kanwadict4.db
kunreihira3.db
passporthira3.db

Copiez ceci sous dist en écrasant.


$ cp `pipenv --venv`/lib/python3.7/site-packages/pykakasi/data/* dist/foo/pykakasi/data/
$ ls dist/foo/pykakasi/data/
hepburndict3.db
itaijidict3.db
kunreidict3.db
passportdict3.db
hepburnhira3.db
kanwadict4.db
kunreihira3.db
passporthira3.db

Quand j'ai exécuté à nouveau le binaire, cela a bien fonctionné comme ci-dessous.


$ dist/foo/foo
bar: Hello!
hoge!

(2020-02-27) Addendum

J'ai trouvé un meilleur moyen, alors je vais l'ajouter. La partie supplémentaire suivante a été exécutée sous Windows.

Page de référence (merci)

La première génération de fichier exécutable a également généré un fichier foo.spec. Modifiez ce fichier comme suit pour ajouter tous les fichiers de dictionnaire pykakasi à a.datas. L'emplacement du fichier de dictionnaire pykakasi dépend de l'environnement, il doit donc être réécrit (dans mon environnement, c'est l'emplacement en bas du lecteur C).

Nous avons également modifié hiddenimports, mais voir cet article.

foo.spec



# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['foo.py'],
             pathex=['C:\\Users\\username\\PycharmProjects\\foo_project'],
             binaries=[],
             datas=[],
-             hiddenimports=[],
+             hiddenimports=['pkg_resources.py2_warn'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
+a.datas += [('pykakasi\\data\\hepburndict3.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\hepburndict3.db', 'DATA')]
+a.datas += [('pykakasi\\data\\hepburnhira3.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\hepburnhira3.db', 'DATA')]
+a.datas += [('pykakasi\\data\\itaijidict3.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\itaijidict3.db', 'DATA')]
+a.datas += [('pykakasi\\data\\kanwadict4.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\kanwadict4.db', 'DATA')]
+a.datas += [('pykakasi\\data\\kunreidict3.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\kunreidict3.db', 'DATA')]
+a.datas += [('pykakasi\\data\\kunreihira3.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\kunreihira3.db', 'DATA')]
+a.datas += [('pykakasi\\data\\passportdict3.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\passportdict3.db', 'DATA')]
+a.datas += [('pykakasi\\data\\passporthira3.db', 'C:\\Users\\username\\.virtualenvs\\d_predict-Evs_tHQX\\lib\\site-packages\\pykakasi\\data\\passporthira3.db', 'DATA')]
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='foo',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='foo')

Utilisez le fichier de spécification réécrit pour générer à nouveau un fichier exécutable.


pipenv run pyinstaller foo.spec

Lorsque j'ai exécuté le binaire généré, cela a bien fonctionné comme ci-dessous.

C:\Users\username\PycharmProjects\foo_project>dist\foo\foo
bar: Hello!
hoge!

Sous le répertoire dist où se trouve le binaire, un sous-répertoire pour pykakasi est créé comme indiqué ci-dessous, et vous pouvez voir que le dictionnaire est copié.

C:\Users\username\PycharmProjects\foo_project>dir .\dist\foo\pykakasi\data

 C:\Users\username\PycharmProjects\foo_project\dist\foo\pykakasi\répertoire de données

    <DIR>          .
    <DIR>          ..
             5,852 hepburndict3.db
             5,649 hepburnhira3.db
            13,981 itaijidict3.db
         7,154,489 kanwadict4.db
             5,843 kunreidict3.db
             5,642 kunreihira3.db
             6,635 passportdict3.db
             6,370 passporthira3.db

C'est tout pour le post-scriptum.

Recommended Posts

Évitez l'erreur d'exécution "KeyError: '_ max_key_len_'" pour les binaires générés par PyInstaller pour le code Python à l'aide de pykakasi
Évitez l'erreur d'exécution ModuleNotFoundError pour les exécutables générés à partir de code Python à l'aide de Pyinstaller
[Python] pour une erreur d'instruction