pytest-orm-boundaries 0.5.0__tar.gz → 0.6.0__tar.gz
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_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/PKG-INFO +29 -14
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/README.md +28 -13
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/pyproject.toml +1 -1
- pytest_orm_boundaries-0.6.0/src/pytest_orm_boundaries/allows.py +26 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/config.py +14 -10
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/crossings.py +18 -10
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/guard.py +3 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/plugin.py +5 -2
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/LICENSE +0 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/__init__.py +0 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/callstack.py +0 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/ignores.py +0 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/model_resolution.py +0 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/prefetch_resolution.py +0 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/report.py +0 -0
- {pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/sql_parsing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-orm-boundaries
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Pytest plugin that fails tests when ORM queries cross DDD aggregate boundaries (Django supported today).
|
|
5
5
|
Keywords: django,pytest,plugin,orm,ddd,aggregate,boundaries,architecture
|
|
6
6
|
Author: Evgeniia Chibisova
|
|
@@ -29,11 +29,11 @@ Description-Content-Type: text/markdown
|
|
|
29
29
|
|
|
30
30
|
# pytest-orm-boundaries
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
💡 **Even if you control your imports, boundaries can still leak through the ORM.**
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
`pytest-orm-boundaries` is a pytest plugin that reports ORM queries crossing your DDD aggregate boundaries.
|
|
35
35
|
|
|
36
|
-
Currently works with Django ORM.
|
|
36
|
+
Currently works with Django ORM, SQLAlchemy is in roadmap.
|
|
37
37
|
|
|
38
38
|
In domain-driven design, an aggregate is a consistency boundary: code in one
|
|
39
39
|
aggregate should not reach into the internals of another. Django's `__` relation
|
|
@@ -44,8 +44,8 @@ lookups make it easy to cross those boundaries silently:
|
|
|
44
44
|
Purchase.objects.get(client__name="John")
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
`pytest-orm-boundaries` watches the
|
|
48
|
-
|
|
47
|
+
`pytest-orm-boundaries` watches the ORM activity exercised by your test suite
|
|
48
|
+
and reports access that crosses a configured boundary - through `__` lookups,
|
|
49
49
|
`select_related`, `prefetch_related`, subqueries, or hand-written `.raw()` SQL.
|
|
50
50
|
|
|
51
51
|
## Install
|
|
@@ -75,8 +75,9 @@ not checked. Without a config file the plugin emits a warning and runs no checks
|
|
|
75
75
|
|
|
76
76
|
## What it catches
|
|
77
77
|
|
|
78
|
-
The plugin flags
|
|
79
|
-
the `purchase` and `client`
|
|
78
|
+
The plugin flags executed ORM access that spans more than one configured group.
|
|
79
|
+
In the DDD example below, each crossing couples the `purchase` and `client`
|
|
80
|
+
aggregates:
|
|
80
81
|
|
|
81
82
|
- `__` relation lookups:
|
|
82
83
|
|
|
@@ -114,7 +115,7 @@ the `purchase` and `client` aggregates:
|
|
|
114
115
|
Purchase.objects.prefetch_related("client")
|
|
115
116
|
```
|
|
116
117
|
|
|
117
|
-
Queries that don't actually join across the boundary are **not** flagged
|
|
118
|
+
Queries that don't actually join across the boundary are **not** flagged - for
|
|
118
119
|
example a foreign-key lookup by id, which Django resolves without a join:
|
|
119
120
|
|
|
120
121
|
```python
|
|
@@ -143,11 +144,22 @@ Each entry names the aggregates the query crossed and the models it joined.
|
|
|
143
144
|
Places are ordered by how many tests they affect. Pass `-v` to see every affected test
|
|
144
145
|
(otherwise the list is capped at 5 per place).
|
|
145
146
|
|
|
146
|
-
##
|
|
147
|
+
## Allow and ignore
|
|
147
148
|
|
|
148
|
-
|
|
149
|
+
CQRS read models may cross boundaries intentionally, also existing application code may contain crossings you want to fix over time. [allow] and [ignore] let you tell the plugin which is which:
|
|
150
|
+
|
|
151
|
+
- `[allow]` - the crossing is **intentional**. Use it for code that is meant to
|
|
152
|
+
span aggregates, such as CQRS read models or cross-aggregate reports. An
|
|
153
|
+
allowed crossing is suppressed and never reported.
|
|
154
|
+
- `[ignore]` - the crossing is **known debt** you plan to fix. It is suppressed
|
|
155
|
+
for now, and the plugin reminds you when an entry is no longer needed.
|
|
149
156
|
|
|
150
157
|
```toml
|
|
158
|
+
[allow]
|
|
159
|
+
files = [
|
|
160
|
+
"app/reports/sales_summary.py",
|
|
161
|
+
]
|
|
162
|
+
|
|
151
163
|
[ignore]
|
|
152
164
|
files = [
|
|
153
165
|
"app/billing.py",
|
|
@@ -155,14 +167,14 @@ files = [
|
|
|
155
167
|
]
|
|
156
168
|
```
|
|
157
169
|
|
|
158
|
-
Each entry is a glob ([`fnmatch`](https://docs.python.org/3/library/fnmatch.html),
|
|
170
|
+
Each entry is a glob ([`fnmatch`](https://docs.python.org/3/library/fnmatch.html)),
|
|
159
171
|
resolved relative to pytest's root directory and matched against either:
|
|
160
172
|
|
|
161
173
|
- the file that issues the query, or
|
|
162
174
|
- the test file.
|
|
163
175
|
|
|
164
|
-
|
|
165
|
-
boundary, the plugin
|
|
176
|
+
An `[ignore]` whose file runs through the whole suite without ever crossing a
|
|
177
|
+
boundary is stale — it is clean now, so the plugin lists it for removal:
|
|
166
178
|
|
|
167
179
|
```
|
|
168
180
|
======================= orm-boundaries: stale ignores ========================
|
|
@@ -171,6 +183,9 @@ Remove them from boundaries.toml:
|
|
|
171
183
|
- app/billing.py
|
|
172
184
|
```
|
|
173
185
|
|
|
186
|
+
`[allow]` entries are never reported this way. If a file sits in both sections,
|
|
187
|
+
the allow wins and its `[ignore]` entry shows up as stale to remove.
|
|
188
|
+
|
|
174
189
|
## A note on Django internals
|
|
175
190
|
|
|
176
191
|
Catching `prefetch_related` relies on Django internals that come with no stability
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# pytest-orm-boundaries
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
💡 **Even if you control your imports, boundaries can still leak through the ORM.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`pytest-orm-boundaries` is a pytest plugin that reports ORM queries crossing your DDD aggregate boundaries.
|
|
6
6
|
|
|
7
|
-
Currently works with Django ORM.
|
|
7
|
+
Currently works with Django ORM, SQLAlchemy is in roadmap.
|
|
8
8
|
|
|
9
9
|
In domain-driven design, an aggregate is a consistency boundary: code in one
|
|
10
10
|
aggregate should not reach into the internals of another. Django's `__` relation
|
|
@@ -15,8 +15,8 @@ lookups make it easy to cross those boundaries silently:
|
|
|
15
15
|
Purchase.objects.get(client__name="John")
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
`pytest-orm-boundaries` watches the
|
|
19
|
-
|
|
18
|
+
`pytest-orm-boundaries` watches the ORM activity exercised by your test suite
|
|
19
|
+
and reports access that crosses a configured boundary - through `__` lookups,
|
|
20
20
|
`select_related`, `prefetch_related`, subqueries, or hand-written `.raw()` SQL.
|
|
21
21
|
|
|
22
22
|
## Install
|
|
@@ -46,8 +46,9 @@ not checked. Without a config file the plugin emits a warning and runs no checks
|
|
|
46
46
|
|
|
47
47
|
## What it catches
|
|
48
48
|
|
|
49
|
-
The plugin flags
|
|
50
|
-
the `purchase` and `client`
|
|
49
|
+
The plugin flags executed ORM access that spans more than one configured group.
|
|
50
|
+
In the DDD example below, each crossing couples the `purchase` and `client`
|
|
51
|
+
aggregates:
|
|
51
52
|
|
|
52
53
|
- `__` relation lookups:
|
|
53
54
|
|
|
@@ -85,7 +86,7 @@ the `purchase` and `client` aggregates:
|
|
|
85
86
|
Purchase.objects.prefetch_related("client")
|
|
86
87
|
```
|
|
87
88
|
|
|
88
|
-
Queries that don't actually join across the boundary are **not** flagged
|
|
89
|
+
Queries that don't actually join across the boundary are **not** flagged - for
|
|
89
90
|
example a foreign-key lookup by id, which Django resolves without a join:
|
|
90
91
|
|
|
91
92
|
```python
|
|
@@ -114,11 +115,22 @@ Each entry names the aggregates the query crossed and the models it joined.
|
|
|
114
115
|
Places are ordered by how many tests they affect. Pass `-v` to see every affected test
|
|
115
116
|
(otherwise the list is capped at 5 per place).
|
|
116
117
|
|
|
117
|
-
##
|
|
118
|
+
## Allow and ignore
|
|
118
119
|
|
|
119
|
-
|
|
120
|
+
CQRS read models may cross boundaries intentionally, also existing application code may contain crossings you want to fix over time. [allow] and [ignore] let you tell the plugin which is which:
|
|
121
|
+
|
|
122
|
+
- `[allow]` - the crossing is **intentional**. Use it for code that is meant to
|
|
123
|
+
span aggregates, such as CQRS read models or cross-aggregate reports. An
|
|
124
|
+
allowed crossing is suppressed and never reported.
|
|
125
|
+
- `[ignore]` - the crossing is **known debt** you plan to fix. It is suppressed
|
|
126
|
+
for now, and the plugin reminds you when an entry is no longer needed.
|
|
120
127
|
|
|
121
128
|
```toml
|
|
129
|
+
[allow]
|
|
130
|
+
files = [
|
|
131
|
+
"app/reports/sales_summary.py",
|
|
132
|
+
]
|
|
133
|
+
|
|
122
134
|
[ignore]
|
|
123
135
|
files = [
|
|
124
136
|
"app/billing.py",
|
|
@@ -126,14 +138,14 @@ files = [
|
|
|
126
138
|
]
|
|
127
139
|
```
|
|
128
140
|
|
|
129
|
-
Each entry is a glob ([`fnmatch`](https://docs.python.org/3/library/fnmatch.html),
|
|
141
|
+
Each entry is a glob ([`fnmatch`](https://docs.python.org/3/library/fnmatch.html)),
|
|
130
142
|
resolved relative to pytest's root directory and matched against either:
|
|
131
143
|
|
|
132
144
|
- the file that issues the query, or
|
|
133
145
|
- the test file.
|
|
134
146
|
|
|
135
|
-
|
|
136
|
-
boundary, the plugin
|
|
147
|
+
An `[ignore]` whose file runs through the whole suite without ever crossing a
|
|
148
|
+
boundary is stale — it is clean now, so the plugin lists it for removal:
|
|
137
149
|
|
|
138
150
|
```
|
|
139
151
|
======================= orm-boundaries: stale ignores ========================
|
|
@@ -142,6 +154,9 @@ Remove them from boundaries.toml:
|
|
|
142
154
|
- app/billing.py
|
|
143
155
|
```
|
|
144
156
|
|
|
157
|
+
`[allow]` entries are never reported this way. If a file sits in both sections,
|
|
158
|
+
the allow wins and its `[ignore]` entry shows up as stale to remove.
|
|
159
|
+
|
|
145
160
|
## A note on Django internals
|
|
146
161
|
|
|
147
162
|
Catching `prefetch_related` relies on Django internals that come with no stability
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pytest-orm-boundaries"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.0"
|
|
8
8
|
description = "Pytest plugin that fails tests when ORM queries cross DDD aggregate boundaries (Django supported today)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Per-file allows: files whose boundary crossings are intentional.
|
|
2
|
+
|
|
3
|
+
Unlike ``[ignore]`` (known debt, tracked for staleness), an ``[allow]`` marks
|
|
4
|
+
architecture that is meant to span aggregates - CQRS read models, cross-aggregate
|
|
5
|
+
reports - so a matching crossing is suppressed and never surfaces as stale.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections.abc import Iterable
|
|
11
|
+
from fnmatch import fnmatch
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AllowList:
|
|
15
|
+
"""Decides whether a crossing's call place is intentional and so allowed.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, *, patterns: Iterable[str]) -> None:
|
|
19
|
+
self._patterns = list(dict.fromkeys(patterns)) # ordered, de-duped
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def is_active(self) -> bool:
|
|
23
|
+
return bool(self._patterns)
|
|
24
|
+
|
|
25
|
+
def has_allow_for(self, *, file_paths: Iterable[str]) -> bool:
|
|
26
|
+
return any(fnmatch(f, p) for f in file_paths for p in self._patterns)
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/config.py
RENAMED
|
@@ -19,7 +19,8 @@ class BoundariesConfig:
|
|
|
19
19
|
"""Parsed and validated content of a ``boundaries.toml``."""
|
|
20
20
|
|
|
21
21
|
aggregates_by_model: dict[str, str] # {"app.model" lower-cased: aggregate_name}
|
|
22
|
-
ignored_files: list[str] #
|
|
22
|
+
ignored_files: list[str] # globs for known debt, tracked for staleness
|
|
23
|
+
allowed_files: list[str] # globs for intentional crossings, never stale
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def discover_config_path(*, explicit: str | None, rootpath: Path) -> Path | None:
|
|
@@ -42,7 +43,8 @@ def load_config(*, path: Path) -> BoundariesConfig:
|
|
|
42
43
|
data = _read_config(path=path)
|
|
43
44
|
return BoundariesConfig(
|
|
44
45
|
aggregates_by_model=_parse_aggregates(data=data, path=path),
|
|
45
|
-
ignored_files=
|
|
46
|
+
ignored_files=_parse_file_globs(data=data, path=path, section_name="ignore"),
|
|
47
|
+
allowed_files=_parse_file_globs(data=data, path=path, section_name="allow"),
|
|
46
48
|
)
|
|
47
49
|
|
|
48
50
|
|
|
@@ -82,23 +84,25 @@ def _parse_aggregates(*, data: dict[str, Any], path: Path) -> dict[str, str]:
|
|
|
82
84
|
return aggregates_by_model
|
|
83
85
|
|
|
84
86
|
|
|
85
|
-
def
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
def _parse_file_globs(
|
|
88
|
+
*, data: dict[str, Any], path: Path, section_name: str
|
|
89
|
+
) -> list[str]:
|
|
90
|
+
"""Read ``[allow]`` and ``[ignore] files`` into a list of glob patterns."""
|
|
91
|
+
section_data = data.get(section_name, {})
|
|
92
|
+
if not isinstance(section_data, dict):
|
|
93
|
+
raise BoundariesConfigError(f"{path}: [{section_name}] must be a table")
|
|
90
94
|
|
|
91
|
-
files =
|
|
95
|
+
files = section_data.get("files", [])
|
|
92
96
|
if not isinstance(files, list):
|
|
93
97
|
raise BoundariesConfigError(
|
|
94
|
-
f"{path}: [
|
|
98
|
+
f"{path}: [{section_name}] files must be a list of glob patterns"
|
|
95
99
|
)
|
|
96
100
|
|
|
97
101
|
patterns: list[str] = []
|
|
98
102
|
for entry in files:
|
|
99
103
|
if not isinstance(entry, str):
|
|
100
104
|
raise BoundariesConfigError(
|
|
101
|
-
f"{path}: [
|
|
105
|
+
f"{path}: [{section_name}] files has a non-string entry: {entry!r}"
|
|
102
106
|
)
|
|
103
107
|
patterns.append(entry)
|
|
104
108
|
return patterns
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/crossings.py
RENAMED
|
@@ -11,6 +11,7 @@ from pytest_orm_boundaries.callstack import find_frames_inside_project
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from collections.abc import Iterable
|
|
13
13
|
|
|
14
|
+
from pytest_orm_boundaries.allows import AllowList
|
|
14
15
|
from pytest_orm_boundaries.ignores import IgnoreTracker
|
|
15
16
|
|
|
16
17
|
|
|
@@ -27,16 +28,19 @@ class CrossingRecord:
|
|
|
27
28
|
|
|
28
29
|
class CrossingTracker:
|
|
29
30
|
"""Checks label sets against the aggregate rule and records the crossings,
|
|
30
|
-
skipping ignored files and naming each crossing's call place and
|
|
31
|
+
skipping allowed and ignored files and naming each crossing's call place and
|
|
32
|
+
test."""
|
|
31
33
|
|
|
32
34
|
def __init__(
|
|
33
35
|
self,
|
|
34
36
|
*,
|
|
35
37
|
aggregates_config: dict[str, str],
|
|
38
|
+
allow_list: AllowList,
|
|
36
39
|
ignore_tracker: IgnoreTracker,
|
|
37
40
|
root: Path,
|
|
38
41
|
) -> None:
|
|
39
42
|
self._aggregates_config = aggregates_config
|
|
43
|
+
self._allow_list = allow_list
|
|
40
44
|
self._ignore_tracker = ignore_tracker
|
|
41
45
|
self._root_path = Path(root)
|
|
42
46
|
self._current_test: str | None = None
|
|
@@ -48,13 +52,16 @@ class CrossingTracker:
|
|
|
48
52
|
|
|
49
53
|
def check(self, *, label_sets: Iterable[Iterable[str]]) -> None:
|
|
50
54
|
"""Record a crossing for each label set that spans aggregates, unless an
|
|
51
|
-
|
|
55
|
+
allow or an ignore covers the call place.
|
|
56
|
+
|
|
57
|
+
Allow wins over ignore: an allowed crossing is suppressed without marking
|
|
58
|
+
the ignore used, so an ignore that only overlaps an allow surfaces as
|
|
59
|
+
stale and can be removed as redundant.
|
|
52
60
|
"""
|
|
53
|
-
# ``frames`` is the in-project part of the call stack
|
|
54
|
-
# for the ignore/stale bookkeeping and to name each crossing's place.
|
|
61
|
+
# ``frames`` is the in-project part of the call stack
|
|
55
62
|
frames: list[tuple[str, int]] | None = None
|
|
56
63
|
file_paths: set[str] | None = None
|
|
57
|
-
if self._ignore_tracker.is_active:
|
|
64
|
+
if self._allow_list.is_active or self._ignore_tracker.is_active:
|
|
58
65
|
frames = find_frames_inside_project(root=self._root_path)
|
|
59
66
|
file_paths = {path for path, _ in frames}
|
|
60
67
|
self._ignore_tracker.mark_seen(file_paths=file_paths)
|
|
@@ -63,11 +70,12 @@ class CrossingTracker:
|
|
|
63
70
|
crossing = self.find_crossing(labels=labels)
|
|
64
71
|
if crossing is None:
|
|
65
72
|
continue
|
|
66
|
-
if file_paths is not None
|
|
67
|
-
file_paths=file_paths
|
|
68
|
-
|
|
69
|
-
self._ignore_tracker.
|
|
70
|
-
|
|
73
|
+
if file_paths is not None:
|
|
74
|
+
if self._allow_list.has_allow_for(file_paths=file_paths):
|
|
75
|
+
continue
|
|
76
|
+
if self._ignore_tracker.has_ignore_for(file_paths=file_paths):
|
|
77
|
+
self._ignore_tracker.mark_used(file_paths=file_paths)
|
|
78
|
+
continue
|
|
71
79
|
if frames is None:
|
|
72
80
|
frames = find_frames_inside_project(root=self._root_path)
|
|
73
81
|
call_place = frames[0] if frames else None
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/guard.py
RENAMED
|
@@ -20,6 +20,7 @@ from pytest_orm_boundaries.sql_parsing import extract_table_names, looks_like_da
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
22
22
|
|
|
23
|
+
from pytest_orm_boundaries.allows import AllowList
|
|
23
24
|
from pytest_orm_boundaries.crossings import CrossingRecord
|
|
24
25
|
from pytest_orm_boundaries.ignores import IgnoreTracker
|
|
25
26
|
|
|
@@ -45,11 +46,13 @@ class BoundaryGuard:
|
|
|
45
46
|
self,
|
|
46
47
|
*,
|
|
47
48
|
aggregates_config: dict[str, str],
|
|
49
|
+
allow_list: AllowList,
|
|
48
50
|
ignore_tracker: IgnoreTracker,
|
|
49
51
|
root: Path,
|
|
50
52
|
) -> None:
|
|
51
53
|
self._tracker = CrossingTracker(
|
|
52
54
|
aggregates_config=aggregates_config,
|
|
55
|
+
allow_list=allow_list,
|
|
53
56
|
ignore_tracker=ignore_tracker,
|
|
54
57
|
root=root,
|
|
55
58
|
)
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/plugin.py
RENAMED
|
@@ -14,6 +14,7 @@ from pytest_orm_boundaries.config import (
|
|
|
14
14
|
discover_config_path,
|
|
15
15
|
load_config,
|
|
16
16
|
)
|
|
17
|
+
from pytest_orm_boundaries.allows import AllowList
|
|
17
18
|
from pytest_orm_boundaries.guard import BoundaryGuard
|
|
18
19
|
from pytest_orm_boundaries.ignores import IgnoreTracker
|
|
19
20
|
|
|
@@ -56,10 +57,12 @@ def _build_guard(*, rootpath: Path, config_path: Path) -> BoundaryGuard | None:
|
|
|
56
57
|
if not config.aggregates_by_model:
|
|
57
58
|
return None
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
allow_list = AllowList(patterns=config.allowed_files)
|
|
61
|
+
ignore_tracker = IgnoreTracker(patterns=config.ignored_files)
|
|
60
62
|
return BoundaryGuard(
|
|
61
63
|
aggregates_config=config.aggregates_by_model,
|
|
62
|
-
|
|
64
|
+
allow_list=allow_list,
|
|
65
|
+
ignore_tracker=ignore_tracker,
|
|
63
66
|
root=rootpath,
|
|
64
67
|
)
|
|
65
68
|
|
|
File without changes
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/__init__.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/callstack.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/ignores.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/report.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.5.0 → pytest_orm_boundaries-0.6.0}/src/pytest_orm_boundaries/sql_parsing.py
RENAMED
|
File without changes
|