albertyw/albertyw.com

View on GitHub
app/notes/20170923-2205.md

Summary

Maintainability
Test Coverage
Bundling Python Packages With PyInstaller and Requests

pyinstaller-requests

1506204304

I recently tried using [PyInstaller](https://github.com/pyinstaller/pyinstaller)
to bundle python applications as a single
binary executable.  Pyinstaller was relatively easy to use and its
documentation is pretty good.  However, I ran into a bit of trouble bundling
the python [requests](https://github.com/requests/requests) package
because of problems with `requests` looking for a trusted certificates file,
usually emitting an error like
`OSError: Could not find a suitable TLS CA certificate bundle, invalid path: ...`.
In a typical installation, the [certifi](https://github.com/certifi/python-certifi)
package includes a set of trusted CA certificates but when PyInstaller bundles
the `requests` and `ceritifi` packages, `certifi` can't provide a file path for
`requests` to use.

The way to fix this is to set the `REQUESTS_CA_BUNDLE` variable
([documentation](http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification))
within your code before using requests:

```python
import pkgutil
import requests
import tempfile

# Read the cert data
cert_data = pkgutil.get_data('certifi', 'cacert.pem')

# Write the cert data to a temporary file
handle = tempfile.NamedTemporaryFile(delete=False)
handle.write(cert_data)
handle.flush()

# Set the temporary file name to an environment variable for the requests package
os.environ['REQUESTS_CA_BUNDLE'] = handle.name

# Make requests using the requests package
requests.get('https://www.albertyw.com/')

# Clean up the temp file
```