pyinstaller-hooks-contrib icon indicating copy to clipboard operation
pyinstaller-hooks-contrib copied to clipboard

hook-pyfiglet.py

Open DeflatedPickle opened this issue 7 years ago • 11 comments

from PyInstaller.utils.hooks import collect_data_files

hiddenimports = ["pyfiglet.fonts"]

datas = collect_data_files ("pyfiglet")

DeflatedPickle avatar Jan 16 '17 21:01 DeflatedPickle

Thanks for this hook. Would you please send a pull-request? And please mind adding

  • the copyright header you can see in the other hooks (mind that we have 2017 now :-)
  • a comment with the url to pyfiglet and
  • which version you have tested it with.

Thanks.

htgoebel avatar Jan 17 '17 10:01 htgoebel

@DeflatedPickle did you actually get this hook to work? I don't think it does with current versions of pyinstaller and pyfiglet. The package uses pkg_resources to load fonts, resulting in errors similar to pyinstaller/pyinstaller#1898:

    f = Figlet(font='slant')
  File "lib\site-packages\pyfiglet\__init__.py", line 710, in __init__
  File "lib\site-packages\pyfiglet\__init__.py", line 717, in setFont
  File "lib\site-packages\pyfiglet\__init__.py", line 90, in __init__
  File "lib\site-packages\pyfiglet\__init__.py", line 100, in preloadFont
  File "lib\site-packages\pkg_resources\__init__.py", line 1191, in resource_exists
  File "lib\site-packages\pkg_resources\__init__.py", line 1459, in has_resource
  File "lib\site-packages\pkg_resources\__init__.py", line 1509, in _has
NotImplementedError: Can't perform this operation for unregistered loader type

So I think this depends on pyinstaller/pyinstaller#2748 unless you provide the font parameter as a filename to avoid using pkg_resources - see below the relevant code for reference:

def preloadFont(cls, font):
        """
        Load font data if exist
        """
        for extension in ('tlf', 'flf'):
            fn = '%s.%s' % (font, extension)
            if pkg_resources.resource_exists('pyfiglet.fonts', fn):
                data = pkg_resources.resource_string('pyfiglet.fonts', fn)
                data = data.decode('UTF-8', 'replace')
                return data
            elif os.path.isfile(font):
                with open(font, 'rb') as f:
                    return f.read().decode('UTF-8', 'replace')
        else:
            raise FontNotFound(font)

nejch avatar Sep 24 '17 22:09 nejch

Was anyone able to get scripts using pyfiglet to work? I tried the above hook which didn't work and then tried updating my spec to include the font files as shown below:

 datas=[('/usr/local/lib/python2.7/site-packages/pyfiglet/fonts','.')],

It creates the executable but when I run it, I get the following:

Traceback (most recent call last):
  File "app.py", line 242, in <module>
    cprint(figlet_format(banner, font="standard"),"blue")
  File "site-packages/pyfiglet/__init__.py", line 43, in figlet_format
  File "site-packages/pyfiglet/__init__.py", line 710, in __init__
  File "site-packages/pyfiglet/__init__.py", line 717, in setFont
  File "site-packages/pyfiglet/__init__.py", line 90, in __init__
  File "site-packages/pyfiglet/__init__.py", line 100, in preloadFont
  File "site-packages/pkg_resources/__init__.py", line 1161, in resource_exists
  File "site-packages/pkg_resources/__init__.py", line 419, in get_provider
ImportError: No module named fonts
Failed to execute script app

I'm kind of surprised that this isn't working considering that a lot of scripts make use of pyfiglet. Thanks.

ossie-git avatar Dec 02 '17 02:12 ossie-git

I'm having the same issue with pyfiglet, even with collect_data_files('pyfiglet'), I get NotImplementedError: Can't perform this operation for unregistered loader type.

@htgoebel Can you confirm that for this ticket to be solved it would take either:

  • pyinstaller/pyinstaller#2748 being implemented
  • pyfiglet stops using pkg_resources
  • use the font name directly so that pyfiglet does not call pkg_resources

Overdrivr avatar Sep 13 '18 09:09 Overdrivr

Does this work?

from PyInstaller.utils.hooks import collect_all

datas, binaries, hiddenimports = collect_all("pyfiglet")

bjones1 avatar Sep 13 '18 13:09 bjones1

Does this work?

from PyInstaller.utils.hooks import collect_all

datas, binaries, hiddenimports = collect_all("pyfiglet")

No, unfortunately it doesn't. This still results in a ModuleNotFoundError on pyfiglet.fonts

SeeDoubleYou avatar Nov 02 '18 15:11 SeeDoubleYou

Hmm. Try running PyInstaller with --log-level=DEBUG and --debug=all. Look at the output of the build to see if pyfiglet files are picked up. Look at the files in dist/ to see what's missing.

bjones1 avatar Nov 02 '18 19:11 bjones1

I've found a workround that has worked for me and might work for other people too, so I'd like to share it. I've added the following as a PyInstaller hook (hook-pyfiglet.py):

Does this work?

from PyInstaller.utils.hooks import collect_all

datas, binaries, hiddenimports = collect_all("pyfiglet")

This seems to have resolved the import issues, as expected, but raised the error NotImplementedError: Can't perform this operation for unregistered loader type, as said in https://github.com/pyinstaller/pyinstaller/issues/2389#issuecomment-420941860.

I've followed what has been discussed in pyinstaller/pyinstaller#2748 and understood that the issue was now related to the fact that a runtime hook was registering the pkg_resources.NullProvider. Since adding another runtime hook wouldn't resolve the problem, as the installed ones would have processed afterwards, I ended up adding the following snippet to my script:

import pkg_resources
import sys

from pyimod03_importers import FrozenImporter

if getattr(sys, 'frozen', False):
   pkg_resources.register_loader_type(FrozenImporter, pkg_resources.DefaultProvider)

In essence, instead of registering NullProvider, we now register FrozenImporter with DefaultProvider, which inherits from NullProvider anyway.

Now, this works for me but I cannot guarantee this doesn't have side effects, use with caution please. Nonetheless, since it has worked for me and the issues haven't been fixed yet, I thought someone might have been interested in a workaround.

I have noticed this issue is dependent on pyinstaller/pyinstaller#2748 , which is itself dependent on another issue. I'm not sure if this workaround helps in figuring out a way of solving any of those issues but if there's any approach you think could be taken, I don't mind trying to help.

caramelomartins avatar Mar 25 '19 23:03 caramelomartins

I understand there is a different issue at hand here, but for anyone looking to quickly use pyfiglet with pyinstaller, doesn't this "just work" by adding a few things to the app.spec? (It seems to work for me.)

hiddenimports=['pyfiglet.fonts'],
datas=[('[insert full path to site packages]/pyfiglet/fonts/standard.flf','pyfiglet/fonts')],

Good luck on the issue everyone. EDIT: You'll also need @caramelomartins snippet.

benduckwdesign avatar Apr 07 '19 22:04 benduckwdesign

Sorry @Thonleb, I don't have a solution for you. Since this is dependent on a few outstanding issues to be properly solved, I guess you can only get something working (hacked) by trial and error. Do you have more details about what "it totally bugs my code" means?

caramelomartins avatar Jul 20 '20 16:07 caramelomartins

@benduckwdesign , great suggestion... My issue was resolved by this!

vaibhavard avatar Jan 12 '22 13:01 vaibhavard