77from mr .data_types import ArtifactsConfig
88from mr .data_types import DefaultArtifactConfig
99from mr .data_types import RepoConfig
10+ from mr .utils import apply_pythonpaths
1011from mr .utils import apply_repo_config
1112from mr .utils import find_python_modules
1213from mr .utils import find_python_packages
@@ -34,13 +35,16 @@ def test_load_repo_config_custom_path_valid_yaml(tmp_path: pathlib.Path):
3435 config_file = tmp_path / "config.yaml"
3536 config_file .write_text (
3637 """
38+ pythonpaths:
39+ - src
3740artifacts:
3841 default_config:
3942 export_step: false
4043 export_3mf: true
4144"""
4245 )
4346 config = load_repo_config (config_file )
47+ assert config .pythonpaths == ["src" ]
4448 assert config .artifacts is not None
4549 assert config .artifacts .default_config .export_step is False
4650 assert config .artifacts .default_config .export_3mf is True
@@ -51,9 +55,68 @@ def test_load_repo_config_empty_yaml_returns_default(tmp_path: pathlib.Path):
5155 config_file = tmp_path / "empty.yaml"
5256 config_file .write_text ("" )
5357 config = load_repo_config (config_file )
58+ assert config .pythonpaths == []
5459 assert config .artifacts is None
5560
5661
62+ def test_apply_pythonpaths_prepends_to_sys_path (
63+ tmp_path : pathlib .Path , monkeypatch : pytest .MonkeyPatch
64+ ):
65+ (tmp_path / "src" ).mkdir ()
66+ config = RepoConfig (pythonpaths = ["src" ])
67+ monkeypatch .chdir (tmp_path )
68+ before = list (__import__ ("sys" ).path )
69+ with apply_pythonpaths (config ) as added :
70+ assert added and added [0 ].endswith ("/src" )
71+ assert __import__ ("sys" ).path [0 ] == added [0 ]
72+ # Ensure we didn't blow away sys.path
73+ assert len (__import__ ("sys" ).path ) >= len (before )
74+ assert __import__ ("sys" ).path == before
75+
76+
77+ def test_apply_pythonpaths_resolves_relative_to_repo_root (
78+ tmp_path : pathlib .Path , monkeypatch : pytest .MonkeyPatch
79+ ):
80+ repo_root = tmp_path / "repo"
81+ (repo_root / "src" ).mkdir (parents = True )
82+ config = RepoConfig (pythonpaths = ["src" ])
83+ monkeypatch .chdir (tmp_path ) # different cwd on purpose
84+ before = list (__import__ ("sys" ).path )
85+ with apply_pythonpaths (config , repo_root = repo_root ) as added :
86+ assert added == [str ((repo_root / "src" ).resolve ())]
87+ assert __import__ ("sys" ).path [0 ] == added [0 ]
88+ assert __import__ ("sys" ).path == before
89+
90+
91+ def test_apply_pythonpaths_does_not_remove_external_duplicate (
92+ tmp_path : pathlib .Path , monkeypatch : pytest .MonkeyPatch
93+ ):
94+ """
95+ If user code adds the same path again during the context, the context manager
96+ should only remove its own inserted occurrence and leave the external one.
97+ """
98+ sys = __import__ ("sys" )
99+ (tmp_path / "src" ).mkdir ()
100+ config = RepoConfig (pythonpaths = ["src" ])
101+ monkeypatch .chdir (tmp_path )
102+
103+ before = list (sys .path )
104+ try :
105+ with apply_pythonpaths (config ) as added :
106+ assert len (added ) == 1
107+ value = added [0 ]
108+ assert sys .path [0 ] == value
109+ # Simulate other code adding the same path during the context.
110+ sys .path .append (value )
111+ assert sys .path .count (value ) == 2
112+ # Our inserted occurrence is removed, but the "external" one remains.
113+ assert value in sys .path
114+ assert sys .path .count (value ) == 1
115+ finally :
116+ # Restore sys.path so this test doesn't affect others.
117+ sys .path [:] = before
118+
119+
57120def test_apply_repo_config_fills_none_from_config ():
58121 """apply_repo_config fills export_step/export_3mf when artifact has None."""
59122
0 commit comments