zyskarch / pytestarch

Test framework for software architecture based on imports between modules.
https://zyskarch.github.io/pytestarch/latest
Apache License 2.0
66 stars 6 forks source link

Rule fails saying that "moduleA" which is imported by "moduleB" using as an aliased relative import is not imported #112

Closed ashok-s-nair closed 1 month ago

ashok-s-nair commented 1 month ago

Label Type: question
Issue Type: Request for clarification

Environment Linux Mint 21.3 (kernel 5.15.0-117-generic), running Python 3.10.12 using pytestarch == 3.0.1

Background

  1. My project path is /home/developer/python/snakes-and-ladders-engine and it has the folder structure:

    ├── src
    │   ├── game
    │   │   └──  game.py
    │   └── utils
    │       └── gameutilities.py
    └── tests
    └──  architecture
        └── test_architecture.py
  2. The gameutilities.py module contains only methods - no classes are defined in the file.

  3. game.py imports gameutilities.py as

    from ..utils import gameutilities as GameUtilities
  4. In test_architecture.py, a pytest fixture returns an evaluable architecture.

    @pytest.fixture
    def game_architecture_instance(project_root: Path, src_root: Path) -> EvaluableArchitecture:
    return get_evaluable_architecture(str(project_root), str(src_root))

Question

I am trying to define the rule "gameutilities should be imported by game" using a pytest test.

def test_utilities_invocation_rule(game_architecture_instance:  EvaluableArchitecture) -> None:
    utils_name: str = "snakes-and-ladders-engine.src.utils.gameutilities"
    game_name: str = "snakes-and-ladders-engine.src.game.game"

    utilities_invocation_rule: Rule = (
        Rule().modules_that()
        .are_named(utils_name)
        .should_only().be_imported_by_modules_that()
        .are_named(game_name)
    )

    utilities_invocation_rule.assert_applies(game_architecture_instance)

This fails with the result

AssertionError: "snakes-and-ladders-engine.src.utils.gameutilities" is not imported by "snakes-and-ladders-engine.src.game.game".

Other functional tests under the test tree work fine, and only the architecture test seems to be failing.

Is the rule misconfigured? What am I doing wrong here? Any support on how to fix this error is much appreciated - thank you!

I have attached the trace of the error as a text file for reference. err_trace.txt

zyskarch commented 1 month ago

Hi,

thanks for the detailed setup description, that made it very easy to reproduce!

The issue lies with the import: With a statement like "from ..X import ..." --> the X is defined as the imported module. So if you set utils_name = "test_games.src.utils", the test passes - but that's not quite what you want to test, I think.

To achieve what you're going for, I'd recommend specifying the import as absolute: import src.utils.gameutilities as GameUtilities. In my test setup, this results in a green test.

Does that solve your problem?

ashok-s-nair commented 1 month ago

Hello @zyskarch Thank you for your prompt and helpful response.

Changing the relative import to an absolute import (import src.utils.gameutilities as GameUtilities) fixed the problem.

Could the point about discouraging relative imports be added (maybe as a footnote or similar) to the README? It might be helpful for other users. Thank you for your consideration.

I'll close this query as resolved.