Vermeiden Sie den Laufzeitfehler "KeyError: '_ max_key_len_'" für Binärdateien, die von PyInstaller für Python-Code mit pykakasi generiert wurden

Artikelinhalt

Bei Python-Code mit pykakasi wurde beim Ausführen der von PyInstaller generierten ausführbaren Datei der Fehler "KeyError: '_ max_key_len_'" angezeigt. Notieren Sie sich, wie Sie dies vermeiden können. Ich verwende Linux (Ubuntu 18.04), Python 3.7.5 und verwende pipenv.

Beispielcode

Code dieses Artikels wurde geändert und verwendet. Ich werde die folgenden 3 Dateien verwenden, um die Binärversion von foo.py zu starten.

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))

Schritte zum Abrufen eines Laufzeitfehlers

Installieren Sie das Modul wie folgt auf Ihrem Terminal:


pipenv install setuptools pykakasi pyinstaller

Die zu diesem Zeitpunkt vorhandenen Dateien lauten wie folgt.


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

Das generierte Pipfile lautet wie folgt.


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

[dev-packages]

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

[requires]
python_version = "3.7"

Führen Sie die folgenden Schritte auf dem Terminal aus, um eine ausführbare Datei zu erstellen.


pipenv run pyinstaller foo.py

Wenn Sie die Datei mit ls überprüfen, werden das Build-Verzeichnis und das dist-Verzeichnis generiert.


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

Da "dist / foo / foo" die ausführbare Datei ist, trat beim Versuch, sie zu verschieben, "KeyError: '_ max_key_len_'" wie unten gezeigt auf.


$ 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

Laufzeitfehler vermeiden

Die Ursache war, dass das Wörterbuch von Pykakashi unter dist unzureichend war. Unter dist gibt es ein Wörterbuch wie unten gezeigt.


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

Auf der anderen Seite gab es 8 Wörterbücher im Installationsziel von 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

Kopieren Sie dies unter dist durch Überschreiben.


$ 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

Als ich die Binärdatei erneut ausführte, funktionierte sie wie folgt.


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

(2020-02-27) Nachtrag

Ich habe einen besseren Weg gefunden, also werde ich ihn hinzufügen. Der folgende zusätzliche Teil wurde unter Windows ausgeführt.

Referenzseite (Danke)

Bei der ersten Generierung ausführbarer Dateien wurde auch eine foo.spec-Datei generiert. Bearbeiten Sie diese Datei wie folgt, um alle Pykakasi-Wörterbuchdateien zu a.datas hinzuzufügen. Der Speicherort der Pykakasi-Wörterbuchdatei hängt von der Umgebung ab, daher muss sie neu geschrieben werden (in meiner Umgebung ist dies der Speicherort unterhalb des Laufwerks C).

Ich habe auch versteckte Importe optimiert, aber siehe diesen Artikel (https://qiita.com/kanedaq/items/e65507878c52ad67d002).

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')

Verwenden Sie die neu geschriebene Spezifikationsdatei, um erneut eine ausführbare Datei zu generieren.


pipenv run pyinstaller foo.spec

Als ich die generierte Binärdatei ausführte, funktionierte sie wie folgt.

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

Unter dem dist-Verzeichnis, in dem sich die Binärdatei befindet, wird wie unten gezeigt ein Unterverzeichnis für pykakasi erstellt, und Sie können sehen, dass das Wörterbuch kopiert wird.

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

 C:\Users\username\PycharmProjects\foo_project\dist\foo\pykakasi\Datenverzeichnis

    <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

Das ist alles für das Postskriptum.

Recommended Posts

Vermeiden Sie den Laufzeitfehler "KeyError: '_ max_key_len_'" für Binärdateien, die von PyInstaller für Python-Code mit pykakasi generiert wurden
Vermeiden Sie Laufzeitfehler ModuleNotFoundError für ausführbare Dateien, die mit Pyinstaller aus Python-Code generiert wurden
[Python] für Anweisungsfehler