0

TL;DR

Importing the requests library fails within a Python3 project when frozen with py2exe. The unfrozen project works. The problem seems to be related to relative imports within the requests module.

long description

I've created a little project using Python3, and would like to turn it into an executable for w32. The project depends on PySide and requests (2.13.0; actually this is a secondary dependency of the used pyapi-gitlab package). All dependencies have been installed via pip3. Python version is 3.4.4 (since PySide doesn't support any later versions of Py3). I'm using py2exe 0.9.2.2.

Everything (e.g. importing and using PySide) works great, but the import requests deep inside fails.

Here's a somewhat minimal example to illustrate the problem:

import logging
logging.basicConfig()
log = logging.getLogger()

import sys
print("Python: %s" % (sys.version,))

try:
    import requests
except ImportError:
    log.fatal("failed to import 'requests'", exc_info=True)

When I run this from the cmdline, I get:

E:\p2e> python p2e.py
Python: 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 19:28:18) [MSC v.1600 32 bit (Intel)]
E:\p2e>

Nice. The following minimal setup.py is supposed to turn this into an exe:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from distutils.core import setup
import py2exe

setup(console=['p2e.py'])

Doing the actual conversion gives a number of "missing modules" warnings:

E:\p2e> python setup.py py2exe
running py2exe

  24 missing Modules                 
  ------------------                 
? Cookie                              imported from requests.compat
? OpenSSL                             imported from requests.packages.urllib3.contrib.pyopenssl
? Queue                               imported from requests.packages.urllib3.connectionpool
? _abcoll                             imported from requests.packages.urllib3.packages.ordered_dict
? backports                           imported from requests.packages.urllib3.packages.ssl_match_hostname
? certifi                             imported from requests.certs
? chardet                             imported from requests.packages
? cookielib                           imported from requests.compat
? cryptography                        imported from requests.packages.urllib3.contrib.pyopenssl
? idna                                imported from requests.models, requests.packages.urllib3.contrib.pyopenssl
? netbios                             imported from uuid
? readline                            imported from cmd, code, pdb
? simplejson                          imported from requests.compat
? six                                 imported from requests.packages.urllib3.contrib.pyopenssl
? socks                               imported from requests.packages.urllib3.contrib.socks
? urllib.getproxies                   imported from requests.compat
? urllib.proxy_bypass                 imported from requests.compat
? urllib.quote                        imported from requests.compat
? urllib.quote_plus                   imported from requests.compat
? urllib.unquote                      imported from requests.compat
? urllib.unquote_plus                 imported from requests.compat
? urllib.urlencode                    imported from requests.compat
? urllib3                             imported from requests.packages
? win32wnet                           imported from uuid
Building 'dist\p2e.exe'.
Building shared code archive 'dist\library.zip'.
Copy c:\windows\system32\python34.dll to dist
Copy C:\Python34\DLLs\_ssl.pyd to dist\_ssl.pyd
Copy C:\Python34\DLLs\_lzma.pyd to dist\_lzma.pyd
Copy C:\Python34\DLLs\select.pyd to dist\select.pyd
Copy C:\Python34\DLLs\_hashlib.pyd to dist\_hashlib.pyd
Copy C:\Python34\DLLs\_ctypes.pyd to dist\_ctypes.pyd
Copy C:\Python34\DLLs\_bz2.pyd to dist\_bz2.pyd
Copy C:\Python34\DLLs\_socket.pyd to dist\_socket.pyd
Copy C:\Python34\DLLs\pyexpat.pyd to dist\pyexpat.pyd
Copy C:\Python34\DLLs\unicodedata.pyd to dist\unicodedata.pyd
E:\p2e>

I routinely ignore these warnings, and run the generated exe:

E:\p2e> dist\p2e.exe
CRITICAL:root:failed to import 'requests'
Traceback (most recent call last):
  File "c:\Python34\lib\site-packages\requests\packages\__init__.py", line 27, in <module>
    from . import urllib3
  File "c:\Python34\lib\site-packages\requests\packages\urllib3\__init__.py", line 8, in <module>
    from .connectionpool import (
  File "c:\Python34\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 28, in <module>
    from .packages.six.moves import queue
  File "c:\Python34\lib\site-packages\requests\packages\urllib3\packages\six.py", line 92, in __get__
    result = self._resolve()
  File "c:\Python34\lib\site-packages\requests\packages\urllib3\packages\six.py", line 115, in _resolve
    return _import_module(self.mod)
  File "c:\Python34\lib\site-packages\requests\packages\urllib3\packages\six.py", line 82, in _import_module
    __import__(name)
ImportError: No module named 'queue'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "p2e.py", line 9, in <module>
  File "c:\Python34\lib\site-packages\requests\__init__.py", line 63, in <module>
    from . import utils
  File "c:\Python34\lib\site-packages\requests\utils.py", line 24, in <module>
    from ._internal_utils import to_native_string
  File "c:\Python34\lib\site-packages\requests\_internal_utils.py", line 11, in <module>
    from .compat import is_py2, builtin_str, str
  File "c:\Python34\lib\site-packages\requests\compat.py", line 11, in <module>
    from .packages import chardet
  File "c:\Python34\lib\site-packages\requests\packages\__init__.py", line 29, in <module>
    import urllib3
ImportError: No module named 'urllib3'
Python: 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 19:28:18) [MSC v.1600 32 bit (Intel)]
E:\p2e>

I'm totally puzzled.

It seems that the requests package does some import magic to - support both included 3rd-party libs (urllib) and libs installed by package managers. - support both Py2 and Py3 (using a local copy of six)

Both seem to create problems.

I can amend the urllib3 problem, by patching requests to only search for that package in relative paths (even though the original code does the same, only enclosed by a try/catch that catches any ImportError and then falls back to import globally.)

I have no idea how to fix the import queue problem.

And after all, it is working properly when I run the script in the Py3 interpreter.

NOTE

There's a similar (maybe the same) issue, but it doesn't include that much information: py2exe "requests" module missing

Community
  • 1
  • 1
umläute
  • 28,885
  • 9
  • 68
  • 122

1 Answers1

2

It looks like urllib3 tries to import the queue module which fails. When that fails, requests fails to import `urllib3.

To force py2exe to include the queue module, use --includes queue when you invoke it.

Ian Stapleton Cordasco
  • 26,944
  • 4
  • 67
  • 72