Python 2.7 basedir重命名后陈旧的pycache导致的ImportMismatchError
Python 2.7 ImportMismatchError caused by stale pycache after basedir rename
我正在努力了解这里发生的事情,以便防止它再次发生。
我有一个 Jenkins 作业 运行 宁一个 python 程序(实际上 pytest
)。它在 virtualenv 中使用 Python 2.7.6。在某些时候,Jenkins 作业被重命名,这会导致 Jenkins 重命名作业工作区存储的目录。通常这不会导致问题,如果它确实发生了 "Wipe Workspace" 往往会解决问题.但是由于特定原因,这没有完成,工作区保持原样。
重命名后,python 程序将拒绝 运行,为特定的 python 模块(conftest.py
)发出 ImportMismatchError
。在使用 pdb
进行一些调试后,我能够计算出 python 模块 (conftest.cpython-27-PYTEST.pyc
) 的缓存版本正在从名为 __pycache__
的目录中加载,并且缓存版本包含现在无效的绝对路径。这会导致 ImportMismatch 错误,因为缓存版本的绝对路径与模块源的绝对路径不匹配,但它仍然被认为是缓存命中!
我知道这个 pycache 机制取代了 "alongside" .pyc
缓存机制 python2 - 但是有几件事我不明白我的情况:
- 既然 Jenkins 使用的是 Python 2.7.6,为什么
__pycache__
存在,而这似乎是从 3.2 开始支持的? Python2 有什么方法可以创建这个目录吗?我注意到它支持创建和读取缓存,这让我感到惊讶 - 这是否向后移植到 2.7.6?
- 为什么这种机制在确定缓存版本是否过时时不考虑模块的完整路径?在这种情况下,python 模块的文件名没有改变,但是 basedir(路径)改变了。但是,这并没有使缓存无效,因此导致了 ImportMismatch 错误。完整路径不应该用作缓存键的一部分而不仅仅是文件名吗?使用旧的
.pyc
机制,重命名 basedir 并不重要,因为 .py
和 .pyc
文件的相对位置和文件名保持不变。
我的修复很简单——我只是删除了 __pycache__
目录。然而,我花了两个小时才走到这一步,主要是因为我以前没有处理过这种缓存机制,所以我想了解更多。
编辑:这是我看到的全部错误消息 - 不幸的是,这里没有提及 __pycache__
目录或删除它们的说明:
+ pytest -s -v
Traceback (most recent call last):
File "/srv2/jenkins/shiningpanda/jobs/bcd7891c/virtualenvs/d41d8cd9/local/lib/python2.7/site-packages/_pytest/config.py", line 362, in _importconftest
mod = conftestpath.pyimport()
File "/srv2/jenkins/shiningpanda/jobs/bcd7891c/virtualenvs/d41d8cd9/local/lib/python2.7/site-packages/py/_path/local.py", line 680, in pyimport
raise self.ImportMismatchError(modname, modfile, self)
ImportMismatchError: ('tests.conftest', '/srv2/jenkins/jobs/CI_Job/workspace/tests/conftest.py', local('/srv2/jenkins/jobs/CI_Job_Renamed/workspace/tests/conftest.py'))
ERROR: could not load /srv2/jenkins/jobs/CI_Job_Renamed/workspace/tests/conftest.py
它存在是因为 pytest 在那里缓存了它重写的字节码(它需要重写它以提供带有简单 assert
的详细断言)。
至于只有basename是key,我猜原因可能和test modules need unique basenames:
的原因一样
Note that using this scheme your test files must have unique names, because pytest will import them as top-level modules since there are no packages to derive a full package name from. In other words, the test files in the example above will be imported as test_app and test_view top-level modules by adding tests/ to sys.path.
至于这是您问题的解决方案 - 错误消息不是告诉您删除 __pycache__
目录吗?绝对应该有。
我正在努力了解这里发生的事情,以便防止它再次发生。
我有一个 Jenkins 作业 运行 宁一个 python 程序(实际上 pytest
)。它在 virtualenv 中使用 Python 2.7.6。在某些时候,Jenkins 作业被重命名,这会导致 Jenkins 重命名作业工作区存储的目录。通常这不会导致问题,如果它确实发生了 "Wipe Workspace" 往往会解决问题.但是由于特定原因,这没有完成,工作区保持原样。
重命名后,python 程序将拒绝 运行,为特定的 python 模块(conftest.py
)发出 ImportMismatchError
。在使用 pdb
进行一些调试后,我能够计算出 python 模块 (conftest.cpython-27-PYTEST.pyc
) 的缓存版本正在从名为 __pycache__
的目录中加载,并且缓存版本包含现在无效的绝对路径。这会导致 ImportMismatch 错误,因为缓存版本的绝对路径与模块源的绝对路径不匹配,但它仍然被认为是缓存命中!
我知道这个 pycache 机制取代了 "alongside" .pyc
缓存机制 python2 - 但是有几件事我不明白我的情况:
- 既然 Jenkins 使用的是 Python 2.7.6,为什么
__pycache__
存在,而这似乎是从 3.2 开始支持的? Python2 有什么方法可以创建这个目录吗?我注意到它支持创建和读取缓存,这让我感到惊讶 - 这是否向后移植到 2.7.6? - 为什么这种机制在确定缓存版本是否过时时不考虑模块的完整路径?在这种情况下,python 模块的文件名没有改变,但是 basedir(路径)改变了。但是,这并没有使缓存无效,因此导致了 ImportMismatch 错误。完整路径不应该用作缓存键的一部分而不仅仅是文件名吗?使用旧的
.pyc
机制,重命名 basedir 并不重要,因为.py
和.pyc
文件的相对位置和文件名保持不变。
我的修复很简单——我只是删除了 __pycache__
目录。然而,我花了两个小时才走到这一步,主要是因为我以前没有处理过这种缓存机制,所以我想了解更多。
编辑:这是我看到的全部错误消息 - 不幸的是,这里没有提及 __pycache__
目录或删除它们的说明:
+ pytest -s -v
Traceback (most recent call last):
File "/srv2/jenkins/shiningpanda/jobs/bcd7891c/virtualenvs/d41d8cd9/local/lib/python2.7/site-packages/_pytest/config.py", line 362, in _importconftest
mod = conftestpath.pyimport()
File "/srv2/jenkins/shiningpanda/jobs/bcd7891c/virtualenvs/d41d8cd9/local/lib/python2.7/site-packages/py/_path/local.py", line 680, in pyimport
raise self.ImportMismatchError(modname, modfile, self)
ImportMismatchError: ('tests.conftest', '/srv2/jenkins/jobs/CI_Job/workspace/tests/conftest.py', local('/srv2/jenkins/jobs/CI_Job_Renamed/workspace/tests/conftest.py'))
ERROR: could not load /srv2/jenkins/jobs/CI_Job_Renamed/workspace/tests/conftest.py
它存在是因为 pytest 在那里缓存了它重写的字节码(它需要重写它以提供带有简单 assert
的详细断言)。
至于只有basename是key,我猜原因可能和test modules need unique basenames:
的原因一样Note that using this scheme your test files must have unique names, because pytest will import them as top-level modules since there are no packages to derive a full package name from. In other words, the test files in the example above will be imported as test_app and test_view top-level modules by adding tests/ to sys.path.
至于这是您问题的解决方案 - 错误消息不是告诉您删除 __pycache__
目录吗?绝对应该有。