1
1
"""Base classes and utilities for pytest-based CLI commands."""
2
2
3
- import os
4
3
import sys
5
4
from abc import ABC , abstractmethod
6
- from contextlib import contextmanager
7
5
from dataclasses import dataclass , field
8
6
from os .path import realpath
9
7
from pathlib import Path
14
12
from rich .console import Console
15
13
16
14
CURRENT_FOLDER = Path (realpath (__file__ )).parent
15
+ PACKAGE_INSTALL_FOLDER = CURRENT_FOLDER .parent .parent
17
16
PYTEST_INI_FOLDER = CURRENT_FOLDER / "pytest_ini_files"
18
- STATIC_TESTS_WORKING_DIRECTORY = CURRENT_FOLDER .parent .parent
19
17
20
18
21
19
@dataclass
@@ -25,7 +23,7 @@ class PytestExecution:
25
23
config_file : Path
26
24
"""Path to the pytest configuration file (e.g., 'pytest-fill.ini')."""
27
25
28
- test_path_args : List [str ] = field (default_factory = list )
26
+ command_logic_test_paths : List [str ] = field (default_factory = list )
29
27
"""List of tests that have to be appended to the start of pytest command arguments."""
30
28
31
29
args : List [str ] = field (default_factory = list )
@@ -44,60 +42,35 @@ def process_args(self, args: List[str]) -> List[str]:
44
42
pass
45
43
46
44
47
- @contextmanager
48
- def chdir (path : Path | None ):
49
- """Context manager to change the current working directory and restore it unconditionally."""
50
- if path is None :
51
- yield
52
- return
53
-
54
- prev_cwd = Path .cwd ()
55
- os .chdir (path )
56
- try :
57
- yield
58
- finally :
59
- os .chdir (prev_cwd )
60
-
61
-
62
45
@dataclass (kw_only = True )
63
46
class PytestRunner :
64
47
"""Handles execution of pytest commands."""
65
48
66
49
console : Console = field (default_factory = lambda : Console (highlight = False ))
67
50
"""Console to use for output."""
68
51
69
- pytest_working_directory : Path | None = None
70
- """
71
- Working directory that pytest should use to start and look for tests.
72
- If set, the working directory of the process will be changed to this directory
73
- before running pytest, and a plugin will be used to change the working directory
74
- back to the original directory to run the rest of the pytest plugins
75
- (so flags like `--input` in `consume` do work with relative paths).
76
- """
77
-
78
52
def run_single (self , execution : PytestExecution ) -> int :
79
53
"""Run pytest once with the given configuration and arguments."""
80
54
root_dir_arg = ["--rootdir" , "." ]
81
55
pytest_args = (
82
56
["-c" , str (execution .config_file )]
83
57
+ root_dir_arg
84
- + execution .test_path_args
58
+ + [
59
+ str (PACKAGE_INSTALL_FOLDER / test_path )
60
+ for test_path in execution .command_logic_test_paths
61
+ ]
85
62
+ execution .args
86
63
)
87
- if self . pytest_working_directory :
64
+ if execution . command_logic_test_paths :
88
65
pytest_args += [
89
66
"-p" ,
90
- "pytest_plugins.working_directory" ,
91
- "--working-directory" ,
92
- f"{ Path .cwd ()} " ,
67
+ "pytest_plugins.fix_package_test_path" ,
93
68
]
94
-
95
69
if self ._is_verbose (execution .args ):
96
70
pytest_cmd = f"pytest { ' ' .join (pytest_args )} "
97
71
self .console .print (f"Executing: [bold]{ pytest_cmd } [/bold]" )
98
72
99
- with chdir (self .pytest_working_directory ):
100
- return pytest .main (pytest_args )
73
+ return pytest .main (pytest_args )
101
74
102
75
def _is_verbose (self , args : List [str ]) -> bool :
103
76
"""Check if verbose output is requested."""
@@ -145,8 +118,8 @@ class PytestCommand:
145
118
plugins : List [str ] = field (default_factory = list )
146
119
"""Plugins to load for the pytest command."""
147
120
148
- static_test_paths : List [Path ] | None = None
149
- """Static tests that contain the command logic."""
121
+ command_logic_test_paths : List [Path ] | None = None
122
+ """Path to test files that contain the command logic."""
150
123
151
124
pytest_ini_folder : Path = PYTEST_INI_FOLDER
152
125
"""Folder where the pytest configuration files are located."""
@@ -159,10 +132,6 @@ def config_path(self) -> Path:
159
132
def execute (self , pytest_args : List [str ]) -> None :
160
133
"""Execute the command with the given pytest arguments."""
161
134
executions = self .create_executions (pytest_args )
162
- if self .static_test_paths :
163
- self .runner .pytest_working_directory = STATIC_TESTS_WORKING_DIRECTORY
164
- else :
165
- self .runner .pytest_working_directory = None
166
135
result = self .runner .run_multiple (executions )
167
136
sys .exit (result )
168
137
@@ -172,8 +141,8 @@ def test_args(self) -> List[str]:
172
141
Return the test-path arguments that have to be appended to all PytestExecution
173
142
instances.
174
143
"""
175
- if self .static_test_paths :
176
- return [str (path ) for path in self .static_test_paths ]
144
+ if self .command_logic_test_paths :
145
+ return [str (path ) for path in self .command_logic_test_paths ]
177
146
return []
178
147
179
148
def create_executions (self , pytest_args : List [str ]) -> List [PytestExecution ]:
@@ -187,7 +156,7 @@ def create_executions(self, pytest_args: List[str]) -> List[PytestExecution]:
187
156
return [
188
157
PytestExecution (
189
158
config_file = self .config_path ,
190
- test_path_args = self .test_args ,
159
+ command_logic_test_paths = self .test_args ,
191
160
args = processed_args ,
192
161
)
193
162
]
0 commit comments