1- """src/pytest_api_cov/ plugin.py """
1+ """pytest plugin for API coverage tracking. """
22
33import importlib
44import importlib .util
@@ -32,7 +32,6 @@ def auto_discover_app() -> Optional[Any]:
3232 """Automatically discover Flask/FastAPI apps in common locations."""
3333 logger .debug ("> Auto-discovering app in common locations..." )
3434
35- # Common file patterns and variable names to check
3635 common_patterns = [
3736 ("app.py" , ["app" , "application" , "main" ]),
3837 ("main.py" , ["app" , "application" , "main" ]),
@@ -45,14 +44,12 @@ def auto_discover_app() -> Optional[Any]:
4544 if os .path .exists (filename ):
4645 logger .debug (f"> Found { filename } , checking for app variables..." )
4746 try :
48- # Import the module
49- module_name = filename [:- 3 ] # Remove .py extension
47+ module_name = filename [:- 3 ] # .py extension
5048 spec = importlib .util .spec_from_file_location (module_name , filename )
5149 if spec and spec .loader :
5250 module = importlib .util .module_from_spec (spec )
5351 spec .loader .exec_module (module )
5452
55- # Check each possible app variable name
5653 for attr_name in attr_names :
5754 if hasattr (module , attr_name ):
5855 app = getattr (module , attr_name )
@@ -112,22 +109,18 @@ def pytest_addoption(parser: pytest.Parser) -> None:
112109
113110def pytest_configure (config : pytest .Config ) -> None :
114111 """Configure the pytest session and logging."""
115- # Configure logging based on verbosity level
116112 if config .getoption ("--api-cov-report" ):
117113 verbosity = config .option .verbose
118114
119- # Set up logging level based on pytest verbosity
120115 if verbosity >= 2 : # -vv or more
121116 log_level = logging .DEBUG
122117 elif verbosity >= 1 : # -v
123118 log_level = logging .INFO
124- else : # normal run
119+ else :
125120 log_level = logging .WARNING
126121
127- # Configure the logger
128122 logger .setLevel (log_level )
129123
130- # Only add handler if we don't already have one
131124 if not logger .handlers :
132125 handler = logging .StreamHandler ()
133126 handler .setLevel (log_level )
@@ -137,7 +130,6 @@ def pytest_configure(config: pytest.Config) -> None:
137130
138131 logger .info ("Initializing API coverage plugin..." )
139132
140- # Register xdist plugin if available
141133 if config .pluginmanager .hasplugin ("xdist" ):
142134 config .pluginmanager .register (DeferXdistPlugin (), "defer_xdist_plugin" )
143135
@@ -157,11 +149,9 @@ def client(request: pytest.FixtureRequest) -> Any:
157149 """
158150 session = request .node .session
159151
160- # Only proceed if API coverage is enabled
161152 if not session .config .getoption ("--api-cov-report" ):
162153 pytest .skip ("API coverage not enabled. Use --api-cov-report flag." )
163154
164- # Try to get app from existing fixture first
165155 app = None
166156 try :
167157 app = request .getfixturevalue ("app" )
@@ -170,13 +160,11 @@ def client(request: pytest.FixtureRequest) -> Any:
170160 logger .debug ("> No 'app' fixture found, trying auto-discovery..." )
171161 app = auto_discover_app ()
172162
173- # If still no app found, show helpful error
174163 if app is None :
175164 helpful_msg = get_helpful_error_message ()
176165 print (helpful_msg )
177166 pytest .skip ("No API app found. See error message above for setup guidance." )
178167
179- # Validate the app is supported
180168 if not is_supported_framework (app ):
181169 pytest .skip (f"Unsupported framework: { type (app ).__name__ } . pytest-api-coverage supports Flask and FastAPI." )
182170
@@ -189,7 +177,6 @@ def client(request: pytest.FixtureRequest) -> Any:
189177 if coverage_data is None :
190178 pytest .skip ("API coverage data not initialized. This should not happen." )
191179
192- # Discover endpoints on the first run of this fixture.
193180 if not coverage_data .discovered_endpoints .endpoints :
194181 try :
195182 endpoints = adapter .get_endpoints ()
@@ -215,15 +202,13 @@ def pytest_sessionfinish(session: pytest.Session) -> None:
215202
216203 logger .debug (f"> pytest-api-coverage: Generating report for { len (coverage_data .recorder )} recorded endpoints." )
217204 if hasattr (session .config , "workeroutput" ):
218- # Send data to master process in serializable format
219205 serializable_recorder = coverage_data .recorder .to_serializable ()
220206 session .config .workeroutput ["api_call_recorder" ] = serializable_recorder
221207 session .config .workeroutput ["discovered_endpoints" ] = coverage_data .discovered_endpoints .endpoints
222208 logger .debug ("> Sent API call data and discovered endpoints to master process" )
223209 else :
224210 logger .debug ("> No workeroutput found, generating report for master data." )
225211
226- # Get worker data from config if available
227212 worker_recorder_data = getattr (session .config , "worker_api_call_recorder" , {})
228213 worker_endpoints = getattr (session .config , "worker_discovered_endpoints" , [])
229214
@@ -247,7 +232,6 @@ def pytest_sessionfinish(session: pytest.Session) -> None:
247232 if hasattr (session , "api_coverage_data" ):
248233 delattr (session , "api_coverage_data" )
249234
250- # Clear any module-level caches
251235 if hasattr (session .config , "worker_api_call_recorder" ):
252236 delattr (session .config , "worker_api_call_recorder" )
253237
@@ -281,7 +265,6 @@ def pytest_testnodedown(self, node: Any) -> None:
281265 node .config .worker_api_call_recorder = current
282266 logger .debug (f"> Updated current data: { current } " )
283267
284- # Merge discovered endpoints (take the first non-empty list we get)
285268 if discovered_endpoints and not getattr (node .config , "worker_discovered_endpoints" , []):
286269 node .config .worker_discovered_endpoints = discovered_endpoints
287270 logger .debug (f"> Set discovered endpoints from worker: { discovered_endpoints } " )
0 commit comments