Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

virtualenv generates python that pre-imports threading (16.x -> 20.x regression) #1895

Closed
navytux opened this issue Jul 9, 2020 · 5 comments · Fixed by #1897
Closed

virtualenv generates python that pre-imports threading (16.x -> 20.x regression) #1895

navytux opened this issue Jul 9, 2020 · 5 comments · Fixed by #1897

Comments

@navytux
Copy link
Contributor

navytux commented Jul 9, 2020

Issue

Hello up there.

After vitualenv upgrade from 16.x to 20.x I've started to get failures with gpython which complains that threading module is already imported at python startup time. It used to work OK before virtualenv rewrite and it still works OK with python -m venv. Virtualenv runtime startup dependency on threading is here added by caae48b ("use import hooks to patch distutils/setuptools (#1688)").

While it is possible to mechanically change threading to _thread.allocate_lock to make gpython nominally happy, in practice it would be more correct to avoid importing and using both threading and low-level _thread, because gevent-based applications depend on being able to patch those modules as early as possible (/cc @jamadden). Before caae48b distutils was patched without importing thread modules, so maybe it is possible to restore that property.

Please find details below.

Thanks beforehand,
Kirill

kirr@deco:~/tmp/trashme$ virtualenv -vvv --with-traceback -p python3 py38.virtualenv
...
(full output from virtualenv creation)
25 setup logging to NOTSET [DEBUG report:42]
47 find interpreter for spec PythonSpec(implementation=CPython, major=3) [INFO builtin:44]
47 proposed PythonInfo(spec=CPython3.8.4.candidate.1-64, exe=/usr/bin/python3, platform=linux, version='3.8.4rc1 (default, Jul  1 2020, 15:31:45) \n[GCC 9.3.0]', encoding_fs_io=utf-8-utf-8) [INFO builtin:50]
47 accepted PythonInfo(spec=CPython3.8.4.candidate.1-64, exe=/usr/bin/python3, platform=linux, version='3.8.4rc1 (default, Jul  1 2020, 15:31:45) \n[GCC 9.3.0]', encoding_fs_io=utf-8-utf-8) [DEBUG builtin:52]
49 filesystem is case-sensitive [DEBUG info:28]
80 create virtual environment via CPython3Posix(dest=/home/kirr/tmp/trashme/py38.virtualenv, clear=False, global=False) [INFO session:52]
80 create folder /home/kirr/tmp/trashme/py38.virtualenv/bin [DEBUG _sync:25]
81 create folder /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages [DEBUG _sync:25]
81 write /home/kirr/tmp/trashme/py38.virtualenv/pyvenv.cfg [DEBUG pyenv_cfg:34]
81      home = /usr [DEBUG pyenv_cfg:38]
81      implementation = CPython [DEBUG pyenv_cfg:38]
81      version_info = 3.8.4.candidate.1 [DEBUG pyenv_cfg:38]
81      virtualenv = 20.0.23+ds [DEBUG pyenv_cfg:38]
81      include-system-site-packages = false [DEBUG pyenv_cfg:38]
81      base-prefix = /usr [DEBUG pyenv_cfg:38]
81      base-exec-prefix = /usr [DEBUG pyenv_cfg:38]
81      base-executable = /usr/bin/python3 [DEBUG pyenv_cfg:38]
81 symlink /usr/bin/python3 to /home/kirr/tmp/trashme/py38.virtualenv/bin/python [DEBUG _sync:44]
82 create virtualenv import hook file /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/_virtualenv.pth [DEBUG api:95]
82 create /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/_virtualenv.py [DEBUG api:98]
82 ============================== target debug ============================== [DEBUG session:54]
82 debug via /home/kirr/tmp/trashme/py38.virtualenv/bin/python /usr/lib/python3/dist-packages/virtualenv/create/debug.py [DEBUG creator:206]
82 {
  "sys": {
    "executable": "/home/kirr/tmp/trashme/py38.virtualenv/bin/python",
    "_base_executable": "/home/kirr/tmp/trashme/py38.virtualenv/bin/python",
    "prefix": "/home/kirr/tmp/trashme/py38.virtualenv",
    "base_prefix": "/usr",
    "real_prefix": null,
    "exec_prefix": "/home/kirr/tmp/trashme/py38.virtualenv",
    "base_exec_prefix": "/usr",
    "path": [
      "/home/kirr/src/tools/txt/docutils/docutils",
      "/usr/lib/python38.zip",
      "/usr/lib/python3.8",
      "/usr/lib/python3.8/lib-dynload",
      "/home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages"
    ],
    "meta_path": [
      "<class '_virtualenv._Finder'>",
      "<class '_frozen_importlib.BuiltinImporter'>",
      "<class '_frozen_importlib.FrozenImporter'>",
      "<class '_frozen_importlib_external.PathFinder'>"
    ],
    "fs_encoding": "utf-8",
    "io_encoding": "utf-8"
  },
  "version": "3.8.4rc1 (default, Jul  1 2020, 15:31:45) \n[GCC 9.3.0]",
  "makefile_filename": "/usr/lib/python3.8/config-3.8-x86_64-linux-gnu/Makefile",
  "os": "<module 'os' from '/usr/lib/python3.8/os.py'>",
  "site": "<module 'site' from '/usr/lib/python3.8/site.py'>",
  "datetime": "<module 'datetime' from '/usr/lib/python3.8/datetime.py'>",
  "math": "<module 'math' (built-in)>",
  "json": "<module 'json' from '/usr/lib/python3.8/json/__init__.py'>"
} [DEBUG session:55]
107 add seed packages via FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, pkg_resources=latest, via=copy, app_data_dir=/home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian) [INFO session:59]
108 Attempting to acquire lock 140007914149536 on /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels.lock [DEBUG filelock:270]
108 Lock 140007914149536 acquired on /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels.lock [INFO filelock:274]
109 get bundled wheel /usr/share/python-wheels/pip-20.1.1-py2.py3-none-any.whl [DEBUG acquire:61]
109 get bundled wheel /usr/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl [DEBUG acquire:61]
109 get bundled wheel /usr/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl [DEBUG acquire:61]
110 get bundled wheel /usr/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl [DEBUG acquire:61]
111 install setuptools from wheel /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels/setuptools-44.0.0-py2.py3-none-any.whl via CopyPipInstall [DEBUG via_app_data:49]
111 install wheel from wheel /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels/wheel-0.34.2-py2.py3-none-any.whl via CopyPipInstall [DEBUG via_app_data:49]
112 install pip from wheel /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels/pip-20.1.1-py2.py3-none-any.whl via CopyPipInstall [DEBUG via_app_data:49]
112 install pkg_resources from wheel /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels/pkg_resources-0.0.0-py2.py3-none-any.whl via CopyPipInstall [DEBUG via_app_data:49]
112 copy /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/setuptools-44.0.0-py2.py3-none-any/setuptools-44.0.0.virtualenv to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/setuptools-44.0.0.virtualenv [DEBUG _sync:52]
112 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/pip-20.1.1-py2.py3-none-any/pip-20.1.1.dist-info to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/pip-20.1.1.dist-info [DEBUG _sync:52]
113 copy /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/pkg_resources-0.0.0-py2.py3-none-any/pkg_resources-0.0.0.virtualenv to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/pkg_resources-0.0.0.virtualenv [DEBUG _sync:52]
114 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/wheel-0.34.2-py2.py3-none-any/wheel to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/wheel [DEBUG _sync:52]
115 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/setuptools-44.0.0-py2.py3-none-any/setuptools-44.0.0.dist-info to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info [DEBUG _sync:52]
115 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/pkg_resources-0.0.0-py2.py3-none-any/pkg_resources-0.0.0.dist-info to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info [DEBUG _sync:52]
118 copy /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/pip-20.1.1-py2.py3-none-any/pip-20.1.1.virtualenv to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/pip-20.1.1.virtualenv [DEBUG _sync:52]
119 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/pkg_resources-0.0.0-py2.py3-none-any/pkg_resources to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/pkg_resources [DEBUG _sync:52]
119 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/pip-20.1.1-py2.py3-none-any/pip to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/pip [DEBUG _sync:52]
121 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/setuptools-44.0.0-py2.py3-none-any/setuptools to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/setuptools [DEBUG _sync:52]
123 copy /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/wheel-0.34.2-py2.py3-none-any/wheel-0.34.2.virtualenv to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/wheel-0.34.2.virtualenv [DEBUG _sync:52]
124 copy directory /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/wheel-0.34.2-py2.py3-none-any/wheel-0.34.2.dist-info to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/wheel-0.34.2.dist-info [DEBUG _sync:52]
130 generated console scripts  [DEBUG base:53]
130 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/wheel to 755 [INFO util:566]
131 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/wheel3 to 755 [INFO util:566]
131 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/wheel-3.8 to 755 [INFO util:566]
131 generated console scripts wheel3 wheel-3.8 wheel [DEBUG base:53]
143 copy /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/image/CopyPipInstall/setuptools-44.0.0-py2.py3-none-any/easy_install.py to /home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/easy_install.py [DEBUG _sync:52]
144 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/easy_install-3.8 to 755 [INFO util:566]
145 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/easy_install3 to 755 [INFO util:566]
145 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/easy_install to 755 [INFO util:566]
146 generated console scripts easy_install3 easy_install-3.8 easy_install [DEBUG base:53]
153 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/pip3.8 to 755 [INFO util:566]
154 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/pip3 to 755 [INFO util:566]
154 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/pip-3.8 to 755 [INFO util:566]
154 changing mode of /home/kirr/tmp/trashme/py38.virtualenv/bin/pip to 755 [INFO util:566]
154 generated console scripts pip3 pip-3.8 pip pip3.8 [DEBUG base:53]
154 Attempting to release lock 140007914149536 on /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels.lock [DEBUG filelock:315]
154 Lock 140007914149536 released on /home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian/3.8/wheels.lock [INFO filelock:318]
154 add activators for Bash, CShell, Fish, PowerShell, Python, Xonsh [INFO session:64]
157 write /home/kirr/tmp/trashme/py38.virtualenv/pyvenv.cfg [DEBUG pyenv_cfg:34]
157     home = /usr [DEBUG pyenv_cfg:38]
157     implementation = CPython [DEBUG pyenv_cfg:38]
157     version_info = 3.8.4.candidate.1 [DEBUG pyenv_cfg:38]
157     virtualenv = 20.0.23+ds [DEBUG pyenv_cfg:38]
157     include-system-site-packages = false [DEBUG pyenv_cfg:38]
157     base-prefix = /usr [DEBUG pyenv_cfg:38]
157     base-exec-prefix = /usr [DEBUG pyenv_cfg:38]
157     base-executable = /usr/bin/python3 [DEBUG pyenv_cfg:38]
157 created virtual environment CPython3.8.4.candidate.1-64 in 134ms
  creator CPython3Posix(dest=/home/kirr/tmp/trashme/py38.virtualenv, clear=False, global=False)
  seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, pkg_resources=latest, via=copy, app_data_dir=/home/kirr/.local/share/virtualenv/seed-app-data/v1.0.1.debian)
  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator [WARNING __main__:21]
kirr@deco:~/tmp/trashme$ . py38.virtualenv/bin/activate
(py38.virtualenv) kirr@deco:~/tmp/trashme$ pip install pip install git+https://lab.nexedi.com/nexedi/pygolang
Collecting git+https://lab.nexedi.com/nexedi/pygolang
  Cloning https://lab.nexedi.com/nexedi/pygolang to /tmp/pip-req-build-wwa_hx8z
  Running command git clone -q https://lab.nexedi.com/nexedi/pygolang /tmp/pip-req-build-wwa_hx8z
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done
Requirement already satisfied: pip in ./py38.virtualenv/lib/python3.8/site-packages (20.1.1)
Collecting install
  Using cached install-1.3.3-py3-none-any.whl (3.1 kB)
Collecting gevent
  Using cached gevent-20.6.2-cp38-cp38-manylinux2010_x86_64.whl (6.1 MB)
Collecting geventmp; python_version >= "3"
  Using cached geventmp-0.0.1-py3-none-any.whl (21 kB)
Collecting six
  Using cached six-1.15.0-py2.py3-none-any.whl (10 kB)
Collecting decorator
  Using cached decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
Requirement already satisfied: setuptools in ./py38.virtualenv/lib/python3.8/site-packages (from gevent->pygolang==0.0.6.post2) (44.0.0)
Collecting greenlet>=0.4.16; platform_python_implementation == "CPython"
  Using cached greenlet-0.4.16-cp38-cp38-manylinux1_x86_64.whl (48 kB)
Collecting zope.event
  Using cached zope.event-4.4-py2.py3-none-any.whl (7.6 kB)
Collecting zope.interface
  Using cached zope.interface-5.1.0-cp38-cp38-manylinux2010_x86_64.whl (243 kB)
Building wheels for collected packages: pygolang
  Building wheel for pygolang (PEP 517) ... done
  Created wheel for pygolang: filename=pygolang-0.0.6.post2-cp38-cp38-linux_x86_64.whl size=4947595 sha256=c2bb28849ce40e479e1d5c328d837df843c48b8e05e589cc043b408751746253
  Stored in directory: /tmp/pip-ephem-wheel-cache-tnp4er72/wheels/0d/6b/51/88bda5290d70335ba062f7a8254de9bac026fc039085d288d1
Successfully built pygolang
Installing collected packages: install, greenlet, zope.event, zope.interface, gevent, geventmp, six, decorator, pygolang
Successfully installed decorator-4.4.2 gevent-20.6.2 geventmp-0.0.1 greenlet-0.4.16 install-1.3.3 pygolang-0.0.6.post2 six-1.15.0 zope.event-4.4 zope.interface-5.1.0
(py38.virtualenv) kirr@deco:~/tmp/trashme$ gpython 
Traceback (most recent call last):
  File "/home/kirr/tmp/trashme/py38.virtualenv/bin/gpython", line 8, in <module>
    sys.exit(main())
  File "/home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/gpython/__init__.py", line 151, in main
    raise RuntimeError('gpython: internal error: the following modules are pre-imported, but must be not:'
RuntimeError: gpython: internal error: the following modules are pre-imported, but must be not:

        ['threading']

sys.modules:

        ['__future__', '__main__', '_abc', '_bootlocale', '_codecs', '_collections', '_collections_abc', '_frozen_importlib', '_frozen_importlib_external', '_functools', '_heapq', '_imp', '_io', '_locale', '_operator', '_signal', '_sitebuiltins', '_sre', '_stat', '_thread', '_virtualenv', '_warnings', '_weakref', '_weakrefset', 'abc', 'builtins', 'codecs', 'collections', 'contextlib', 'copyreg', 'encodings', 'encodings.aliases', 'encodings.latin_1', 'encodings.utf_8', 'enum', 'functools', 'genericpath', 'gpython', 'heapq', 'importlib', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib.abc', 'importlib.machinery', 'importlib.util', 'io', 'itertools', 'keyword', 'marshal', 'operator', 'os', 'os.path', 'posix', 'posixpath', 're', 'reprlib', 'site', 'sitecustomize', 'sre_compile', 'sre_constants', 'sre_parse', 'stat', 'sys', 'threading', 'time', 'types', 'warnings', 'zipimport', 'zope']

For the record here is how it works with older virtualenv and python -m venv:

kirr@deco:~/tmp/trashme$ python3 -m venv py38.venv
kirr@deco:~/tmp/trashme$ . py38.venv/bin/activate
(py38.venv) kirr@deco:~/tmp/trashme$ pip install git+https://lab.nexedi.com/nexedi/pygolang
Collecting git+https://lab.nexedi.com/nexedi/pygolang
  Cloning https://lab.nexedi.com/nexedi/pygolang to /tmp/pip-req-build-scmc7bpn
  Running command git clone -q https://lab.nexedi.com/nexedi/pygolang /tmp/pip-req-build-scmc7bpn
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done
Collecting geventmp; python_version >= "3"
  Using cached geventmp-0.0.1-py3-none-any.whl (21 kB)
Collecting six
  Using cached six-1.15.0-py2.py3-none-any.whl (10 kB)
Collecting decorator
  Using cached decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
Collecting gevent
  Using cached gevent-20.6.2-cp38-cp38-manylinux2010_x86_64.whl (6.1 MB)
Collecting zope.interface
  Using cached zope.interface-5.1.0-cp38-cp38-manylinux2010_x86_64.whl (243 kB)
Requirement already satisfied: setuptools in ./py38.venv/lib/python3.8/site-packages (from gevent->pygolang==0.0.6.post2) (44.0.0)
Collecting greenlet>=0.4.16; platform_python_implementation == "CPython"
  Using cached greenlet-0.4.16-cp38-cp38-manylinux1_x86_64.whl (48 kB)
Collecting zope.event
  Using cached zope.event-4.4-py2.py3-none-any.whl (7.6 kB)
Building wheels for collected packages: pygolang
  Building wheel for pygolang (PEP 517) ... done
  Created wheel for pygolang: filename=pygolang-0.0.6.post2-cp38-cp38-linux_x86_64.whl size=4947579 sha256=4075e7b9e11c03396244307e2a504786f748406664b8a0a9ae0b855c0557888b
  Stored in directory: /tmp/pip-ephem-wheel-cache-ph49sx0j/wheels/0d/6b/51/88bda5290d70335ba062f7a8254de9bac026fc039085d288d1
Successfully built pygolang
Installing collected packages: zope.interface, greenlet, zope.event, gevent, geventmp, six, decorator, pygolang
Successfully installed decorator-4.4.2 gevent-20.6.2 geventmp-0.0.1 greenlet-0.4.16 pygolang-0.0.6.post2 six-1.15.0 zope.event-4.4 zope.interface-5.1.0
(py38.venv) kirr@deco:~/tmp/trashme$ gpython 
Python 3.8.4rc1 (default, Jul  1 2020, 15:31:45) 
[GCC 9.3.0] [GPython 0.0.6.post2] [gevent 20.6.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 

Environment

Provide at least:

  • OS: Debian GNU/Linux testing Linux deco 5.7.0-1-amd64 #1 SMP Debian 5.7.6-1 (2020-06-24) x86_64 GNU/Linux
  • pip list of the host python where virtualenv is installed:
kirr@deco:~$ pip list
Package              Version
-------------------- --------------
appdirs              1.4.4
asciinema            2.0.2
atomicwrites         1.3.0
attrs                19.3.0
backcall             0.2.0
beautifulsoup4       4.9.1
bleach               3.1.5
blinker              1.4
breezy               3.1.0
Brlapi               0.7.0
brz-etckeeper        0.0.0
certifi              2020.4.5.1
chardet              3.0.4
colorama             0.4.3
configobj            5.0.6
cryptography         2.8
cupshelpers          1.0
cycler               0.10.0
dblatex              0.3.11py3
dbus-python          1.2.16
decorator            4.4.2
Deprecated           1.2.10
devscripts           2.20.4
distlib              0.3.0
distro               1.5.0
docutils             0.16
dulwich              0.20.2
entrypoints          0.3
fastimport           0.9.8
feedparser           5.2.1
filelock             3.0.12
flake8               3.8.3
gevent               1.4.0
gpg                  1.13.1-unknown
greenlet             0.4.15
gyp                  0.1
html5lib             1.0.1
httplib2             0.18.1
idna                 2.9
importlib-metadata   1.6.0
iotop                0.6
ipython              7.16.1
ipython-genutils     0.2.0
jedi                 0.17.0
jeepney              0.4.3
keyring              18.0.1
kiwisolver           1.0.1
launchpadlib         1.10.13
lazr.restfulclient   0.14.2
lazr.uri             1.0.4
louis                3.14.0
lxml                 4.5.0
Markdown             3.2.2
Markups              3.0.0
matplotlib           3.2.2
mccabe               0.6.1
meld                 3.20.2
meson                0.54.3
more-itertools       4.2.0
mpmath               1.1.0
musicbrainzngs       0.7.1
mutagen              1.44.0
mypy                 0.782
mypy-extensions      0.4.3
notify2              0.3
numpy                1.18.4
oauthlib             3.1.0
olefile              0.46
packaging            20.3
parso                0.7.0
patiencediff         0.1.0
pexpect              4.6.0
pickleshare          0.7.5
Pillow               7.0.0
pip                  20.1.1
pkginfo              1.4.2
pluggy               0.13.0
prompt-toolkit       3.0.5
psutil               5.7.0
pulsemixer           1.5.1
py                   1.8.1
pycairo              1.16.2
pycodestyle          2.6.0
pycups               1.9.73
pycurl               7.43.0.2
pyflakes             2.2.0
pygame               1.9.6
PyGithub             1.43.7
Pygments             2.3.1
PyGObject            3.36.0
pyinotify            0.9.6
PyJWT                1.7.1
pyparsing            2.4.7
PyQt5                5.15.0
PyQtWebEngine        5.15.0
PySimpleSOAP         1.16.2
pysmbc               1.0.22
pytest               4.6.11
python-apt           2.1.3
python-dateutil      2.8.1
python-debian        0.1.37
python-debianbts     3.0.2
python-gitlab        2.3.1
python-ly            0.9.6
python-magic         0.4.16
python-markdown-math 0.7
python-poppler-qt5   0.75.0
pyxattr              0.6.1
pyxdg                0.26
PyYAML               5.3.1
quodlibet            4.3.0
readme-renderer      24.0
regex                2019.8.19
reportbug            7.6.0
reportlab            3.5.34
requests             2.23.0
requests-toolbelt    0.8.0
rfc3986              1.4.0
roman                2.0.0
scour                0.37
SecretStorage        3.1.2
setuptools           46.1.3
simplejson           3.17.0
sip                  4.19.23
six                  1.15.0
soupsieve            2.0.1
sympy                1.6
textile              4.0.1
tqdm                 4.43.0
traitlets            4.3.3
twine                3.2.0
typed-ast            1.4.1
typing-extensions    3.7.4.2
unidiff              0.5.5
urllib3              1.25.9
virtualenv           20.0.23+ds
wadllib              1.3.4
wcwidth              0.1.9
webencodings         0.5.1
wheel                0.34.2
wrapt                1.11.2
youtube-dl           2020.6.16.1
zipp                 1.0.0
@navytux navytux added the bug label Jul 9, 2020
@gaborbernat
Copy link
Contributor

gaborbernat commented Jul 9, 2020

Before caae48b distutils was patched without importing thread modules, so maybe it is possible to restore that property.

Earlier patchings broke other workflows while also imposing significant maintenance overheads, so that path is a no go from me.

because gevent-based applications depend on being able to patch those modules as early as possible (/cc @jamadden).

Wait, this is odd, how come gpython must patch at first import. IMHO this requirement doesn't make much sense, and I'd advocate for dropping this for gpython.

Alternatively, we could disable distutils patching with gpython, given we can somehow identify that gpython is active 🤷

@gaborbernat gaborbernat added question and removed bug labels Jul 9, 2020
@navytux
Copy link
Contributor Author

navytux commented Jul 10, 2020

@gaborbernat thanks for feedback.

Gevent-based applications need to patch threading, socket, ssl, etc modules in order to change standard library to use lightweight greenlets instead of OS-threads. This patching has to be performed as early as possible in the lifetime of the process in order to avoid situation when part of the program uses functions that are greenlet-aware, and part of the program uses "the same function" - e.g. for threading.Lock - that are not greenlet aware. If the latter case is not avoided it usually results in hangs and deadlocks. Please read more about it here:

http://www.gevent.org/intro.html#monkey-patching

Note: it is not only gpython who needs this. It is all gevent-based programs that use gevent via stdlib-compatible API. And there are many such programs. Gevent also provides a way to run programs simalar to gpython - via python -m gevent.monkey ...

Maybe if there would be a mechanism for gpython/gevent to tell to virtualenv to run part of its code as early as possible - in particular before virtualenv imports threading - that would indeed help.

Kirill

@gaborbernat
Copy link
Contributor

Thinking this through I think would solve this use case and avoid the problem if we'd construct the lock at first call within find_spec, rather than upfront. At which point distutils/setuptools gets called event should already be setup (potentially either via a pth file, or site customize).

@navytux
Copy link
Contributor Author

navytux commented Jul 10, 2020

@gaborbernat, thanks. Do you mean something like this:

diff --git a/src/virtualenv/create/via_global_ref/_virtualenv.py b/src/virtualenv/create/via_global_ref/_virtualenv.py
index b399da4..9a8e7c9 100644
--- a/src/virtualenv/create/via_global_ref/_virtualenv.py
+++ b/src/virtualenv/create/via_global_ref/_virtualenv.py
@@ -39,18 +39,35 @@ def parse_config_files(self, *args, **kwargs):
     # https://docs.python.org/3/library/importlib.html#setting-up-an-importer
     from importlib.abc import MetaPathFinder
     from importlib.util import find_spec
-    from threading import Lock
     from functools import partial
 
     class _Finder(MetaPathFinder):
         """A meta path finder that allows patching the imported distutils modules"""
 
         fullname = None
-        lock = Lock()
+
+        # lock[0] is threading.Lock(), but initialized lazily to avoid importing
+        # threading very early at startup, because there are gevent-based
+        # applications that need to be first to import threading by themselves.
+        # See /~https://github.com/pypa/virtualenv/issues/1895 for details.
+        lock = []
 
         def find_spec(self, fullname, path, target=None):
             if fullname in _DISTUTILS_PATCH and self.fullname is None:
-                with self.lock:
+                # initialize lock[0] lazily
+                if len(self.lock) == 0:
+                    import threading
+                    lock = threading.Lock()
+                    # there is possibility that two threads T1 and T2 are
+                    # simultaneously running into find_spec, observing .lock as
+                    # empty, and further going into hereby initialization.
+                    # However due to the GIL, list.append() operation is atomic
+                    # and this way only one of the threads will "win" to put
+                    # the lock - that every thread will use - into .lock[0].
+                    # https://docs.python.org/3/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
+                    self.lock.append(lock)
+
+                with self.lock[0]:
                     self.fullname = fullname
                     try:
                         spec = find_spec(fullname, path)

?

I don't have offhand experience with virtualenv codebase on where and how to put the test that after python startup, threading is not imported. Would you please complete the patch or point me into right direction wrt tests?

Kirill

navytux added a commit to navytux/virtualenv that referenced this issue Jul 14, 2020
Gevent-based applications need to be able to import threading, socket,
ssl, etc... modules early to be able to monkey-patch them to use
lightweight greenlets instead of OS threads. This patching has to be
done as early as possible in the lifetime of the process

http://www.gevent.org/intro.html#monkey-patching

However starting from caae48b (use import hooks to patch
distutils/setuptools (pypa#1688)) threading became always preimported which,
for example, rendered gpython[1] unusable:

	(py38.virtualenv) kirr@deco:~/tmp/trashme$ gpython
	Traceback (most recent call last):
	  File "/home/kirr/tmp/trashme/py38.virtualenv/bin/gpython", line 8, in <module>
	    sys.exit(main())
	  File "/home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/gpython/__init__.py", line 151, in main
	    raise RuntimeError('gpython: internal error: the following modules are pre-imported, but must be not:'
	RuntimeError: gpython: internal error: the following modules are pre-imported, but must be not:

	        ['threading']

	sys.modules:

	        ['__future__', '__main__', '_abc', '_bootlocale', '_codecs', '_collections', '_collections_abc', '_frozen_importlib', '_frozen_importlib_external', '_functools', '_heapq', '_imp', '_io', '_locale', '_operator', '_signal', '_sitebuiltins', '_sre', '_stat', '_thread', '_virtualenv', '_warnings', '_weakref', '_weakrefset', 'abc', 'builtins', 'codecs', 'collections', 'contextlib', 'copyreg', 'encodings', 'encodings.aliases', 'encodings.latin_1', 'encodings.utf_8', 'enum', 'functools', 'genericpath', 'gpython', 'heapq', 'importlib', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib.abc', 'importlib.machinery', 'importlib.util', 'io', 'itertools', 'keyword', 'marshal', 'operator', 'os', 'os.path', 'posix', 'posixpath', 're', 'reprlib', 'site', 'sitecustomize', 'sre_compile', 'sre_constants', 'sre_parse', 'stat', 'sys', 'threading', 'time', 'types', 'warnings', 'zipimport', 'zope']

Fix it by importing threading lazily.

Fixes: pypa#1895

[1] https://pypi.org/project/pygolang/#gpython
navytux added a commit to navytux/virtualenv that referenced this issue Jul 14, 2020
Gevent-based applications need to be able to import threading, socket,
ssl, etc... modules early to be able to monkey-patch them to use
lightweight greenlets instead of OS threads. This patching has to be
done as early as possible in the lifetime of the process

http://www.gevent.org/intro.html#monkey-patching

However starting from caae48b (use import hooks to patch
distutils/setuptools (pypa#1688)) threading became always preimported which,
for example, rendered gpython[1] unusable:

	(py38.virtualenv) kirr@deco:~/tmp/trashme$ gpython
	Traceback (most recent call last):
	  File "/home/kirr/tmp/trashme/py38.virtualenv/bin/gpython", line 8, in <module>
	    sys.exit(main())
	  File "/home/kirr/tmp/trashme/py38.virtualenv/lib/python3.8/site-packages/gpython/__init__.py", line 151, in main
	    raise RuntimeError('gpython: internal error: the following modules are pre-imported, but must be not:'
	RuntimeError: gpython: internal error: the following modules are pre-imported, but must be not:

	        ['threading']

	sys.modules:

	        ['__future__', '__main__', '_abc', '_bootlocale', '_codecs', '_collections', '_collections_abc', '_frozen_importlib', '_frozen_importlib_external', '_functools', '_heapq', '_imp', '_io', '_locale', '_operator', '_signal', '_sitebuiltins', '_sre', '_stat', '_thread', '_virtualenv', '_warnings', '_weakref', '_weakrefset', 'abc', 'builtins', 'codecs', 'collections', 'contextlib', 'copyreg', 'encodings', 'encodings.aliases', 'encodings.latin_1', 'encodings.utf_8', 'enum', 'functools', 'genericpath', 'gpython', 'heapq', 'importlib', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib.abc', 'importlib.machinery', 'importlib.util', 'io', 'itertools', 'keyword', 'marshal', 'operator', 'os', 'os.path', 'posix', 'posixpath', 're', 'reprlib', 'site', 'sitecustomize', 'sre_compile', 'sre_constants', 'sre_parse', 'stat', 'sys', 'threading', 'time', 'types', 'warnings', 'zipimport', 'zope']

Fix it by importing threading lazily.

Fixes: pypa#1895

[1] https://pypi.org/project/pygolang/#gpython
@navytux
Copy link
Contributor Author

navytux commented Jul 14, 2020

OK, I've filed #1897.

@pypa pypa locked and limited conversation to collaborators Jan 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants