PyInstaller not working with module pycountry?

1,251 views
Skip to first unread message

RapidTech 1898

unread,
Sep 17, 2020, 5:16:22 AM9/17/20
to PyInstaller

Normally PyInstaller works fine for me but i saw a problem using the python-module pycountry.

I tried this very simple code:

import pycountry
land="DE" country = pycountry.countries.get (alpha_2=land)
print(country.name)  

Compiled it with pyinstaller: 
pyinstaller --onefile xyz.py

But i want to execute the compiled exe i get this error:  
Traceback (most recent call last):
File "temp2.py", line 1, in <module> import pycountry File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 677, in _load_unlocked File "c:\users\polzi\appdata\local\programs\python\python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module exec(bytecode, module.__dict__) File "site-packages\pycountry\__init__.py", line 12, in <module> File "site-packages\pkg_resources\__init__.py", line 481, in get_distribution File "site-packages\pkg_resources\__init__.py", line 357, in get_provider File "site-packages\pkg_resources\__init__.py", line 900, in require File "site-packages\pkg_resources\__init__.py", line 786, in resolve pkg_resources.DistributionNotFound: The 'pycountry' distribution was not found and is required by the application [45548] Failed to execute script temp2  

bwoodsend

unread,
Sep 17, 2020, 11:03:47 AM9/17/20
to PyInstaller

Presumably pycountry uses pkg_resources.get_distribution("pycountry") somewhere to access its own metadata (usually to set a __version__ attribute). But PyInstaller doesn’t collect that by default. To include it you need to use the spec file. It looks like your code is named temp2.py so your spec file will be called temp2.spec. Open temp2.spec (it’s just a Python script so you can use your Python editor). Then put the following at the top:

from PyInstaller.utils.hooks import copy_metadata

And in the a = Analysis(...) section change:

    datas = [],

to

    datas = copy_metadata("pycountry"),

Then rebuild using:

PyInstaller --clean temp2.spec

RapidTech 1898

unread,
Sep 18, 2020, 2:10:56 AM9/18/20
to PyInstaller
Thanks very much - works perfect!

So when i want to compile a py-file with pyinstaller is it necessary to make the 2 steps:
1) compile the program "normally": pyinstaller --onefile temp2.py
2) make the changes in the spec-file and run:  pyInstaller --clean temp2.spec  

Or is it also possible to this in 1 step?


bwoodsend

unread,
Sep 18, 2020, 9:07:21 AM9/18/20
to PyInstaller
Umm, yes and no. For your step 1 you can use `pyi-makespec --onefile temp2.py` which will generate the spec file (instant) without launching a build (slow). Then proceed to your step 2. So it's two commands but it only builds once.

RapidTech 1898

unread,
Sep 29, 2020, 3:33:36 AM9/29/20
to PyInstaller
Oh great - thanks for the detailed explanation!

Tim Grove

unread,
Sep 29, 2020, 3:33:39 AM9/29/20
to pyins...@googlegroups.com
You only need to go through 2 steps the first time you do this. Create your .spec file and amend it as needed, saving it with a different name so as not overwrite it. Then you will only have to run 1 step in the future:

pyinstaller my_temp2.spec

On Fri, 18 Sep 2020 14:07 bwoodsend, <bwoo...@gmail.com> wrote:
Umm, yes and no. For your step 1 you can use `pyi-makespec --onefile temp2.py` which will generate the spec file (instant) without launching a build (slow). Then proceed to your step 2. So it's two commands but it only builds once.

--
You received this message because you are subscribed to the Google Groups "PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyinstaller...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyinstaller/3af7dae7-8029-456e-bac9-828652e99762n%40googlegroups.com.

RapidTech 1898

unread,
Sep 30, 2020, 4:16:34 AM9/30/20
to PyInstaller
OK - i see thanks.

So i create this spec-file one time - change it - and save it with another name

Then when i have a py-program which uses pycountry again i have to:
- rename the spec-file to the name of the (new) python-program - eg. NewProgram.spec
- and then run one time: pyinstaller - --clean NewProgram.spec  -onefile NewProgram.py

(or is the --clean comamnd not more necessary here - cause he takes it auomatically with the above statement?)

bwoodsend

unread,
Oct 2, 2020, 3:49:21 AM10/2/20
to PyInstaller

If you want to recycle fixes for a specific library then you can create a hook for it which you can copy between projects. In this case it would be a file called hook-pycountry.py containing:

 from PyInstaller.utils.hooks import copy_metadata  
 datas = copy_metadata("pycountry")

Put it in the same folder as your main code and add --additional-hooks-dir=. to your build command. (Note you must always use --clean when you add/change a hook.) With this you can go back to using PyInstaller my_code.py and ignore the spec file. If you prefer the spec then add '.' to the hookspath=[].

Once your happy with it you may send the hook to the hooks repo and it’ll be included in the next release. Then all you’d have to do upgrade to the latest release:

pip install -U pyinstaller-hooks-contrib

And you can forget about all of this…

RapidTech 1898

unread,
Oct 4, 2020, 5:33:55 AM10/4/20
to PyInstaller
OK - i tried this out @bwoodsend

Created the hook-pycountry.py file you described it.

And then i tried it to compile the exe-file with: pyinstaller --onefile --additional-hooks-dir=. temp5.py

The creation of the temp5.exe file was sucessful - but when i try to start the exe-file i get this error message:
Traceback (most recent call last):
  File "temp5.py", line 3, in <module>
  File "pycountry\db.py", line 40, in load_if_needed
  File "pycountry\db.py", line 69, in _load
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Polzi\\AppData\\Local\\Temp\\_MEI114722\\pycountry\\databases\\iso3166-1.json'
[42284] Failed to execute script temp5

Have i misunderstood something?
Thanks for your patience...

bwoodsend

unread,
Oct 5, 2020, 2:39:30 AM10/5/20
to PyInstaller

Looks like pycountry also contains data files (which PyInstaller also doesn’t collect by default). There’s a hook utility for that too (although it’s odd we haven’t seen this sooner). Your hook becomes:

from PyInstaller.utils.hooks import copy_metadata, collect_data_files
datas = copy_metadata("pycountry") + collect_data_files("pycountry")

RapidTech 1898

unread,
Oct 13, 2020, 6:49:25 AM10/13/20
to PyInstaller
Thank you very much!
Works great now.
Reply all
Reply to author
Forward
0 new messages