Pyinstaller created executable failing in _build_ssl_context (shotgun_api3\lib\httplib2\python3\__init__.py)

I’ve created a small, standalone python tool with a user interface window created in PyQT (PySide2 module).

I’m using pyinstaller to create a standalone executable, but whenever I try to run the executable I get this traceback (below).

Traceback (most recent call last):
  File "artintegration.py", line 38, in <module>
    class SGInteract():
  File "artintegration.py", line 54, in SGInteract
    sg = shotgun_api3.Shotgun(sgURL, login=sgLogin, password=sgPass)
  File "shotgun_api3\shotgun.py", line 677, in __init__
  File "shotgun_api3\shotgun.py", line 721, in server_caps
  File "shotgun_api3\shotgun.py", line 776, in info
  File "shotgun_api3\shotgun.py", line 3232, in _call_rpc
  File "shotgun_api3\shotgun.py", line 3372, in _make_call
  File "shotgun_api3\shotgun.py", line 3426, in _http_request
  File "shotgun_api3\lib\httplib2\python3\__init__.py", line 1763, in request
  File "shotgun_api3\lib\httplib2\python3\__init__.py", line 1239, in __init__
  File "shotgun_api3\lib\httplib2\python3\__init__.py", line 194, in _build_ssl_context
FileNotFoundError: [Errno 2] No such file or directory

This is the code at that location in the Shotgun API code:

def _build_ssl_context(
    disable_ssl_certificate_validation, ca_certs, cert_file=None, key_file=None,
    maximum_version=None, minimum_version=None, key_password=None,
):
    if not hasattr(ssl, "SSLContext"):
        raise RuntimeError("httplib2 requires Python 3.2+ for ssl.SSLContext")
    context = ssl.SSLContext(DEFAULT_TLS_VERSION)
    context.verify_mode = (
        ssl.CERT_NONE if disable_ssl_certificate_validation else ssl.CERT_REQUIRED
    )
    # SSLContext.maximum_version and SSLContext.minimum_version are python 3.7+.
    # source: https://docs.python.org/3/library/ssl.html#ssl.SSLContext.maximum_version
    if maximum_version is not None:
        if hasattr(context, "maximum_version"):
            context.maximum_version = getattr(ssl.TLSVersion, maximum_version)
        else:
            ...

This happens whether I use the “One Directory” (–onedir) or the “One File” (–onefile) options.
These are the commands I’ve used:

pyinstaller --onedir --windowed --hiddenimport xmlrpc  --hiddenimport xmlrpc.client --debug all -y artintegration.py
pyinstaller --onefile --windowed --hiddenimport xmlrpc  --hiddenimport xmlrpc.client --debug all -y artintegration.py

Is it that it can’t find the path to the stored SSL Certificates?

3 Likes

NOTE:
line 194 of that init.py module is a blank line immediately following this:

context.verify_mode = (
    ssl.CERT_NONE if disable_ssl_certificate_validation else ssl.CERT_REQUIRED
)

Hi

I am having the same issue/error message trying to create a standalone executable with pyinstaller. Did you get anywhere with this problem?

Cheers

Hi @Michael_Rich & @pata,

Having trouble finding someone with knowledge about pyinstaller on our side as it’s not something we support, hoping that someone in the community might be able to offer some clarity?

-David

Pyinstaller will only pull in the the code files, not the data files embedded in the site packages.

In order to force it to do so, you need to use the command-line flag --add-data "src/file.txt:dest"

So in your specific case, you need to bundle the cacerts.txt file into your your distributable build. It can be a bit tricky finding the right path for src and dest.

If you are using OSX or Linux, I suggest that you add the following part to your command line:

--add-data "`python -c 'import shotgun_api3; from shotgun_api3.lib.httplib2 import certs; import os; cacerts = certs.where(); print("%s:shotgun_api3%s" % (cacerts, os.path.dirname(cacerts[len(shotgun_api3.__path__[0]):])))'`"

This will:

  • use your current default python binary and run it thanks to the back-ticks
  • load the shotgun_api3 package
  • locate the certificate file (the src:file.txt part)
  • do the correct manipulation indicate where the file should go (the dest part)
  • assemble the two in the correct form, separated by a : and print it out surrounded by double quotes (in case there is a space in the paths)

If you are on Windows… you will need to work these for yourself by running python like this in a shell: python -c "from shotgun_api3.lib.httplib2 import certs; print( certs.where())"

From the result, you will see which cert file is used, and where to put it. Hint: strip all up to the slash after site-packages. Be careful with the back-quotes on Windows, where you see one you may need to use 2 so that an actual back-quote is inserted and not an escaped character.

Good luck and let us know how this worked out,

-Patrick

2 Likes