Skip to content

Windows: ImportError loading conftest due to path casing regression (pytest 5.1.2) #17

@rowan-stein

Description

@rowan-stein

User's report

5.1.2 ImportError while loading conftest (windows import folder casing issues)
5.1.1 works fine. after upgrade to 5.1.2, the path was converted to lower case

Installing collected packages: pytest
  Found existing installation: pytest 5.1.1
    Uninstalling pytest-5.1.1:
      Successfully uninstalled pytest-5.1.1
Successfully installed pytest-5.1.2
PS C:\Azure\KMS\ComponentTest\Python> pytest --collect-only .\PIsys -m smoke
ImportError while loading conftest 'c:\azure\kms\componenttest\python\pisys\conftest.py'.
ModuleNotFoundError: No module named 'python'
PS C:\Azure\KMS\ComponentTest\Python>

Additional context from affected users

  • Importing from package with uppercase components (e.g., muepy.imageProcessing.wafer.sawStreets) fails with ModuleNotFoundError: No module named 'muepy.imageprocessing' (note the lowercase p).
  • This occurs after upgrading from pytest 5.1.1 to 5.1.2 on Windows 10.

pytest output

(%PREFIX%) %SRC_DIR%>pytest --pyargs muepy
============================= test session starts =============================
platform win32 -- Python 3.6.7, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: %SRC_DIR%
collected 0 items / 1 errors

=================================== ERRORS ====================================
________________________ ERROR collecting test session ________________________
..\_test_env\lib\site-packages\_pytest\config\__init__.py:440: in _importconftest
    return self._conftestpath2mod[conftestpath]
E   KeyError: local('c:\\users\\angelo.peronio\\appdata\\local\\continuum\\miniconda3\\envs\\packaging\\conda-bld\\muepy_1567627432048\\_test_env\\lib\\site-packages\\muepy\\imageprocessing\\wafer\\sawstreets\\tests\\conftest.py')

During handling of the above exception, another exception occurred:
..\_test_env\lib\site-packages\_pytest\config\__init__.py:446: in _importconftest
    mod = conftestpath.pyimport()
..\_test_env\lib\site-packages\py\_path\local.py:701: in pyimport
    __import__(modname)
E   ModuleNotFoundError: No module named 'muepy.imageprocessing'

During handling of the above exception, another exception occurred:
..\_test_env\lib\site-packages\py\_path\common.py:377: in visit
    for x in Visitor(fil, rec, ignore, bf, sort).gen(self):
..\_test_env\lib\site-packages\py\_path\common.py:429: in gen
    for p in self.gen(subdir):
..\_test_env\lib\site-packages\py\_path\common.py:429: in gen
    for p in self.gen(subdir):
..\_test_env\lib\site-packages\py\_path\common.py:429: in gen
    for p in self.gen(subdir):
..\_test_env\lib\site-packages\py\_path\common.py:418: in gen
    dirs = self.optsort([p for p in entries
..\_test_env\lib\site-packages\py\_path\common.py:419: in <listcomp>
    if p.check(dir=1) and (rec is None or rec(p))])
..\_test_env\lib\site-packages\_pytest\main.py:606: in _recurse
    ihook = self.gethookproxy(dirpath)
..\_test_env\lib\site-packages\_pytest\main.py:424: in gethookproxy
    my_conftestmodules = pm._getconftestmodules(fspath)
..\_test_env\lib\site-packages\_pytest\config\__init__.py:420: in _getconftestmodules
    mod = self._importconftest(conftestpath)
..\_test_env\lib\site-packages\_pytest\config\__init__.py:454: in _importconftest
    raise ConftestImportFailure(conftestpath, sys.exc_info())
E   _pytest.config.ConftestImportFailure: (local('c:\\users\\angelo.peronio\\appdata\\local\\continuum\\miniconda3\\envs\\packaging\\conda-bld\\muepy_1567627432048\\_test_env\\lib\\site-packages\\muepy\\imageprocessing\\wafer\\sawstreets\\tests\\conftest.py'), (<class 'ModuleNotFoundError'>, ModuleNotFoundError("No module named 'muepy.imageprocessing'",), <traceback object at 0x0000018F0D6C9A48>))
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!
============================== 1 error in 1.32s ===============================

Specification (by Emerson Gray)

Root cause:

  • Regression introduced by using os.path.normcase in path normalization (PR 5792), which lowercases paths on Windows.
  • Lowercased paths are used during conftest import, causing module-name derivation in lowercase and mismatches when conftest imports packages using case-preserved names (e.g., imageProcessing).

Fix strategy:

  • Continue using unique_path (normcase) for cache/dedup keys to avoid duplicate conftest loading across differently cased paths.
  • Use a case-preserving real path for the actual import operations:
    • In _pytest/config/__init__.py::PytestPluginManager._importconftest, derive pkgpath and call pyimport() using conftestpath.realpath() (case-preserving) while keeping unique_path(conftestpath) only for internal caches.

Proposed code changes:

  • File: pytest/src/_pytest/config/__init__.py
  • Function: PytestPluginManager._importconftest
  • Changes:
    • Replace direct use of unique_path(conftestpath) for pyimport with two variables:
      • conftestpath_key = unique_path(conftestpath) (normcased, for caches)
      • real_conftestpath = conftestpath.realpath() (case-preserving, for import)
    • Use real_conftestpath.pypkgpath() and real_conftestpath.pyimport() for module import.
    • Store mod in _conftestpath2mod keyed by conftestpath_key.
    • Update _dirpath2confmods keyed by conftestpath_key.dirpath().
    • Raise ConftestImportFailure with real_conftestpath for clearer error output.

Regression test:

  • File: pytest/testing/test_windows_conftest_import_casing.py
  • Behavior:
    • Skip on non-Windows.
    • Create a package imageProcessing/subpkg/helper.py with FOO = 1.
    • In conftest.py, import imageProcessing.subpkg.helper (mixed case) and assert helper.FOO == 1.
    • Add a trivial test to trigger conftest import; ensure collection succeeds.

Backward compatibility:

  • Retains deduplication benefits of unique_path while restoring correct module-name derivation on Windows.
  • Non-Windows behavior unchanged.

Reproduction steps

  1. On Windows, create a package with uppercase letters in directory names.
  2. Use a conftest.py that imports a submodule using the mixed-case package name.
  3. Run pytest to collect tests; observe ImportError while loading conftest in 5.1.2.
  4. With the proposed fix, collection should succeed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions