Skip to content

AttributeError: Test modules cannot use parent module's attributes under --import-mode=importlib #10337

Description

@akhilramkee
  • a detailed description of the bug or problem you are having
  • output of pip list from the virtual environment you are using
  • pytest and operating system versions
  • minimal example if possible

Description of the bug:
Pytest when executed under --import-mode=importlib doesn't try to retain the child module as parent module's attribute if parent module is already in sys.path. This started happening in pytest 7.1.3 after enabling doctest to respect import-mode in #10088.

Minimal Example

File structure

pytest_importlib_issue/
├── __init__.py
├── temp.py
└── tests/
    └── test_temp.py

temp.py

def x():
    """
    >>> assert 1==1
    """
    return 2

test_temp.py

import pytest_importlib_issue
from pytest_importlib_issue import temp

def test_x():
    assert temp.x() == 2
    assert pytest_importlib_issue.temp.x() == 2

Output - MacOS 12.6

pytest7.1.3 without importlib

(pytest7.1.3) akhileshr@Akhileshs-MacBook-Air /tmp % pytest pytest_importlib_issue --doctest-modules                                       
============================================================================================================ test session starts =============================================================================================================
platform darwin -- Python 3.9.10, pytest-7.1.3, pluggy-0.13.1
rootdir: /private/tmp
plugins: anyio-3.5.0, xdist-2.2.1, easyread-0.1.0, forked-1.3.0
collected 2 items                                                                                                                                                                                                                            

pytest_importlib_issue/temp.py .                                                                                                                                                                                                       [ 50%]
pytest_importlib_issue/tests/test_temp.py .                                                                                                                                                                                            [100%]

============================================================================================================= 2 passed in 0.03s ==============================================================================================================

pytest-7.1.3 with importlib

(pytest7.1.3) akhileshr@Akhileshs-MacBook-Air /tmp % pytest pytest_importlib_issue --import-mode=importlib --doctest-modules                                             
============================================================================================================ test session starts =============================================================================================================
platform darwin -- Python 3.9.10, pytest-7.1.3, pluggy-0.13.1
rootdir: /private/tmp
plugins: anyio-3.5.0, xdist-2.2.1, easyread-0.1.0, forked-1.3.0
collected 2 items                                                                                                                                                                                                                            

pytest_importlib_issue/temp.py .                                                                                                                                                                                                       [ 50%]
pytest_importlib_issue/tests/test_temp.py F                                                                                                                                                                                            [100%]

================================================================================================================== FAILURES ==================================================================================================================
___________________________________________________________________________________________________________________ test_x ___________________________________________________________________________________________________________________

    def test_x():
        assert temp.x() == 2
>       assert pytest_importlib_issue.temp.x() == 2
E       AttributeError: module 'pytest_importlib_issue' has no attribute 'temp'

pytest_importlib_issue/tests/test_temp.py:6: AttributeError
========================================================================================================== short test summary info ===========================================================================================================
FAILED pytest_importlib_issue/tests/test_temp.py::test_x - AttributeError: module 'pytest_importlib_issue' has no attribute 'temp'
======================================================================================================== 1 failed, 1 passed in 0.08s =========================================================================================================

It could be seen that the failure happens when we try to access the child module through parent module.

pytest-7.0.1 with importlib

(pytest7.0.1) akhileshr@Akhileshs-MacBook-Air /tmp % pytest pytest_importlib_issue --import-mode=importlib --doctest-modules
============================================================================================================ test session starts =============================================================================================================
platform darwin -- Python 3.9.10, pytest-7.0.1, pluggy-0.13.1
rootdir: /private/tmp
plugins: anyio-3.5.0, xdist-2.2.1, easyread-0.1.0, forked-1.3.0
collected 2 items                                                                                                                                                                                                                            

pytest_importlib_issue/temp.py .                                                                                                                                                                                                       [ 50%]
pytest_importlib_issue/tests/test_temp.py .                                                                                                                                                                                            [100%]

============================================================================================================= 2 passed in 0.03s ==============================================================================================================

This passes, because doctest-modules were using prepend instead of importlib before the PR. ( added this to state this is a recent issue ).

Fix: Child module has to be persisted in Parent module as an attribute similar to how importlib.import_module does.

Activity

  1. akhilramkee commented on Oct 4, 2022

    @akhilramkee
    ContributorAuthor

    Have the required fix lined up in #10338. Please let me know if it looks good or I am missing something.

    Thanks!

  2. akhilramkee commented on Nov 1, 2022

    @akhilramkee
    ContributorAuthor

    any thoughts on this ? @nicoddemus / @RonnyPfannschmidt / @bluetech

  3. jaraco commented on Jun 29, 2023

    @jaraco
    Contributor

    This issue also affects pmxbot.

    I created an even smaller repro with one namespace package, one submodule, and one test:

     draft @ tree
    .
    ├── pkg
    │   └── mod.py
    └── tests
        └── test_something.py
    
    3 directories, 2 files
     draft @ cat pkg/mod.py
     draft @ cat tests/test_something.py
    import pkg.mod
    
    
    def test_mod():
        pkg.mod
    
     draft @ pip-run pytest -- -m pytest --doctest-modules --import-mode importlib
    ========================================================================= test session starts ==========================================================================
    platform darwin -- Python 3.11.4, pytest-7.4.0, pluggy-1.2.0
    rootdir: /Users/jaraco/draft
    plugins: anyio-3.6.2
    collected 1 item                                                                                                                                                       
    
    tests/test_something.py F                                                                                                                                        [100%]
    
    =============================================================================== FAILURES ===============================================================================
    _______________________________________________________________________________ test_mod _______________________________________________________________________________
    
        def test_mod():
    >       pkg.mod
    E       AttributeError: module 'pkg' has no attribute 'mod'
    
    tests/test_something.py:5: AttributeError
    ======================================================================= short test summary info ========================================================================
    FAILED tests/test_something.py::test_mod - AttributeError: module 'pkg' has no attribute 'mod'
    ========================================================================== 1 failed in 0.02s ===========================================================================
    

    Remove --doctest-modules or --import-mode importlib or move tests/test_something.py to . and the test passes.

    Also confirmed that the bugfix proposed in #10338 fixes the issue:

     draft @ pip-run 'pytest@git+https://github.com/akhilramkee/pytest@importlib-parent' -- -m pytest --import-mode importlib --doctest-modules
    ========================================================================= test session starts ==========================================================================
    platform darwin -- Python 3.11.4, pytest-7.2.0.dev265+g9118b95f, pluggy-1.2.0
    rootdir: /Users/jaraco/draft
    plugins: anyio-3.6.2
    collected 1 item                                                                                                                                                       
    
    tests/test_something.py .                                                                                                                                        [100%]
    
    ========================================================================== 1 passed in 0.01s ===========================================================================
    
  4. jaraco commented on Jun 29, 2023

    @jaraco
    Contributor

    I've also confirmed that with this fix, pmxbot is able to adopt native namespace packages without the test suite failing (pmxbot/pmxbot#110).

    Thanks Akhil for the report and fix.

  5. nicoddemus commented on Jul 1, 2023

    @nicoddemus
    Member

    any thoughts on this ? @nicoddemus / @RonnyPfannschmidt / @bluetech

    Really sorry, I seem to have missed this.

    Yeah looks great, it is only missing a changelog entry which I will push up shortly.

    Would you like to have your name added to AUTHORS as well @akhilramkee ?

  6. added a commit that references this issue on Jul 1, 2023
    2f7415c
  7. akhilramkee commented on Jul 1, 2023

    @akhilramkee
    ContributorAuthor

    Yeah looks great, it is only missing a changelog entry which I will push up shortly.

    Thanks @nicoddemus for taking care of the missing changelog.

    Would you like to have your name added to AUTHORS as well @akhilramkee ?

    Sure, I would like that. I can add myself to the AUTHORS in a separate PR if that works.

  8. added 2 commits that reference this issue on Apr 18, 2026
    495946b
    136511b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: collectionrelated to the collection phasetype: bugproblem that needs to be addressed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions