pytest-api-cov 1.1.0__py3-none-any.whl → 1.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pytest_api_cov/report.py CHANGED
@@ -30,31 +30,59 @@ def categorise_endpoints(
30
30
  ) -> Tuple[List[str], List[str], List[str]]:
31
31
  """Categorise endpoints into covered, uncovered, and excluded.
32
32
 
33
- Exclusion patterns support simple wildcard matching:
33
+ Exclusion patterns support simple wildcard matching with negation:
34
34
  - Use * for wildcard (matches any characters)
35
+ - Use ! at the start to negate a pattern (include what would otherwise be excluded)
35
36
  - All other characters are matched literally
36
- - Examples: "/admin/*", "/health", "/docs/*"
37
+ - Examples: "/admin/*", "/health", "!users/bob" (negates exclusion)
38
+ - Pattern order matters: exclusions are applied first, then negations override them
37
39
  """
38
40
  covered, uncovered, excluded = [], [], []
39
41
 
40
- compiled_patterns = (
41
- [re.compile("^" + re.escape(pattern).replace(r"\*", ".*") + "$") for pattern in exclusion_patterns]
42
- if exclusion_patterns
43
- else None
44
- )
42
+ if not exclusion_patterns:
43
+ compiled_exclusions = None
44
+ compiled_negations = None
45
+ else:
46
+ # Separate exclusion and negation patterns
47
+ exclusion_only = [p for p in exclusion_patterns if not p.startswith("!")]
48
+ negation_only = [p[1:] for p in exclusion_patterns if p.startswith("!")] # Remove the '!' prefix
49
+
50
+ compiled_exclusions = (
51
+ [re.compile("^" + re.escape(pattern).replace(r"\*", ".*") + "$") for pattern in exclusion_only]
52
+ if exclusion_only
53
+ else None
54
+ )
55
+ compiled_negations = (
56
+ [re.compile("^" + re.escape(pattern).replace(r"\*", ".*") + "$") for pattern in negation_only]
57
+ if negation_only
58
+ else None
59
+ )
45
60
 
46
61
  for endpoint in endpoints:
47
62
  # Check exclusion patterns against both full "METHOD /path" and just "/path"
48
63
  is_excluded = False
49
- if compiled_patterns:
64
+ if compiled_exclusions:
50
65
  # Extract path from "METHOD /path" format for pattern matching
51
66
  if " " in endpoint:
52
67
  _, path_only = endpoint.split(" ", 1)
53
- is_excluded = any(p.match(endpoint) for p in compiled_patterns) or any(
54
- p.match(path_only) for p in compiled_patterns
68
+ is_excluded = any(p.match(endpoint) for p in compiled_exclusions) or any(
69
+ p.match(path_only) for p in compiled_exclusions
70
+ )
71
+ else:
72
+ is_excluded = any(p.match(endpoint) for p in compiled_exclusions)
73
+
74
+ # Check negation patterns - these override exclusions
75
+ if is_excluded and compiled_negations:
76
+ if " " in endpoint:
77
+ _, path_only = endpoint.split(" ", 1)
78
+ is_negated = any(p.match(endpoint) for p in compiled_negations) or any(
79
+ p.match(path_only) for p in compiled_negations
55
80
  )
56
81
  else:
57
- is_excluded = any(p.match(endpoint) for p in compiled_patterns)
82
+ is_negated = any(p.match(endpoint) for p in compiled_negations)
83
+
84
+ if is_negated:
85
+ is_excluded = False # Negation overrides exclusion
58
86
 
59
87
  if is_excluded:
60
88
  excluded.append(endpoint)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytest-api-cov
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Pytest Plugin to provide API Coverage statistics for Python Web Frameworks
5
5
  Author-email: Barnaby Gill <barnabasgill@gmail.com>
6
6
  License: Apache-2.0
@@ -259,14 +259,17 @@ show_uncovered_endpoints = true
259
259
  show_covered_endpoints = false
260
260
  show_excluded_endpoints = false
261
261
 
262
- # Exclude endpoints from coverage using simple wildcard patterns
262
+ # Exclude endpoints from coverage using wildcard patterns with negation support
263
263
  # Use * for wildcard matching, all other characters are matched literally
264
+ # Use ! at the start to negate a pattern (include what would otherwise be excluded)
264
265
  exclusion_patterns = [
265
266
  "/health", # Exact match
266
267
  "/metrics", # Exact match
267
268
  "/docs/*", # Wildcard: matches /docs/swagger, /docs/openapi, etc.
268
269
  "/admin/*", # Wildcard: matches all admin endpoints
269
- "/api/v1.0/*" # Exact version match (won't match /api/v1x0/*)
270
+ "!/admin/public", # Negation: include /admin/public even though /admin/* excludes it
271
+ "/api/v1.0/*", # Exact version match (won't match /api/v1x0/*)
272
+ "!/api/v1.0/health" # Negation: include /api/v1.0/health even though /api/v1.0/* excludes it
270
273
  ]
271
274
 
272
275
  # Save detailed JSON report
@@ -308,9 +311,12 @@ pytest --api-cov-report --api-cov-show-uncovered-endpoints=false
308
311
  # Save JSON report
309
312
  pytest --api-cov-report --api-cov-report-path=api_coverage.json
310
313
 
311
- # Exclude specific endpoints (supports wildcards)
314
+ # Exclude specific endpoints (supports wildcards and negation)
312
315
  pytest --api-cov-report --api-cov-exclusion-patterns="/health" --api-cov-exclusion-patterns="/docs/*"
313
316
 
317
+ # Exclude with negation (exclude all admin except admin/public)
318
+ pytest --api-cov-report --api-cov-exclusion-patterns="/admin/*" --api-cov-exclusion-patterns="!/admin/public"
319
+
314
320
  # Verbose logging (shows discovery process)
315
321
  pytest --api-cov-report -v
316
322
 
@@ -5,9 +5,9 @@ pytest_api_cov/frameworks.py,sha256=0_8ZzVbeZ6U1ZZwuzCn82m-q5NcRlIOTtocV5zeIGd0,
5
5
  pytest_api_cov/models.py,sha256=AW7X4DzzsY-HtNsQMm5x55x95Q-10B2xhD9_XaXFDBw,5997
6
6
  pytest_api_cov/plugin.py,sha256=o2fqQv3M5HzlPYGXm-rDBxbPRHbiMEPpImJ4a5tum0s,16540
7
7
  pytest_api_cov/pytest_flags.py,sha256=oGTCv7T_Mj439PFrvB3LawmLFQYppZOOS1f_HOK1cJE,2408
8
- pytest_api_cov/report.py,sha256=hUBEIjK0TXEnamWV61_w6AZKHLh5mD0eXcrmTs61baQ,7600
9
- pytest_api_cov-1.1.0.dist-info/METADATA,sha256=uznGlaFxXlXM2FnGtRTtyDqM_nPerAaTMt8ubTQQvxY,12841
10
- pytest_api_cov-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
- pytest_api_cov-1.1.0.dist-info/entry_points.txt,sha256=hWqEhsBKzbwSwcxCzKgSA8NElQxk0K4PKERrYsi3csk,110
12
- pytest_api_cov-1.1.0.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
13
- pytest_api_cov-1.1.0.dist-info/RECORD,,
8
+ pytest_api_cov/report.py,sha256=0VOg_YqdpCLfTY2nltUeW8xgeqJnb2-8_oyeIObXFL0,8975
9
+ pytest_api_cov-1.1.1.dist-info/METADATA,sha256=AO5Ih7vuA1X3tRxmy4XExYvtQA5Lm3wgNXeMbq_wKt0,13314
10
+ pytest_api_cov-1.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
+ pytest_api_cov-1.1.1.dist-info/entry_points.txt,sha256=hWqEhsBKzbwSwcxCzKgSA8NElQxk0K4PKERrYsi3csk,110
12
+ pytest_api_cov-1.1.1.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
13
+ pytest_api_cov-1.1.1.dist-info/RECORD,,