pytest-orm-boundaries 0.6.0__tar.gz → 0.7.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.6.0 → pytest_orm_boundaries-0.7.0}/PKG-INFO +12 -7
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/README.md +11 -6
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/pyproject.toml +1 -1
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/config.py +35 -5
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/report.py +2 -2
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/LICENSE +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/__init__.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/allows.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/callstack.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/crossings.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/guard.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/ignores.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/model_resolution.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/plugin.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/prefetch_resolution.py +0 -0
- {pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.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.7.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
|
|
@@ -60,14 +60,19 @@ pytest discovers the plugin automatically.
|
|
|
60
60
|
|
|
61
61
|
## Configure
|
|
62
62
|
|
|
63
|
-
Declare your aggregates in `boundaries.toml` at the project
|
|
64
|
-
the file with `--boundaries-config` / the
|
|
63
|
+
Declare your aggregates and their Django models in `boundaries.toml` at the project
|
|
64
|
+
root (or point at the file with `--boundaries-config` / the
|
|
65
|
+
`boundaries_config` ini option):
|
|
65
66
|
|
|
66
67
|
```toml
|
|
67
|
-
[aggregates]
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
[aggregates.client]
|
|
69
|
+
models = ["bookshop.Client"]
|
|
70
|
+
|
|
71
|
+
[aggregates.book]
|
|
72
|
+
models = ["bookshop.Book"]
|
|
73
|
+
|
|
74
|
+
[aggregates.purchase]
|
|
75
|
+
models = ["bookshop.Purchase", "bookshop.PurchaseLine"]
|
|
71
76
|
```
|
|
72
77
|
|
|
73
78
|
Models are written as `app_label.Model`. Models not listed in any aggregate are
|
|
@@ -31,14 +31,19 @@ pytest discovers the plugin automatically.
|
|
|
31
31
|
|
|
32
32
|
## Configure
|
|
33
33
|
|
|
34
|
-
Declare your aggregates in `boundaries.toml` at the project
|
|
35
|
-
the file with `--boundaries-config` / the
|
|
34
|
+
Declare your aggregates and their Django models in `boundaries.toml` at the project
|
|
35
|
+
root (or point at the file with `--boundaries-config` / the
|
|
36
|
+
`boundaries_config` ini option):
|
|
36
37
|
|
|
37
38
|
```toml
|
|
38
|
-
[aggregates]
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
[aggregates.client]
|
|
40
|
+
models = ["bookshop.Client"]
|
|
41
|
+
|
|
42
|
+
[aggregates.book]
|
|
43
|
+
models = ["bookshop.Book"]
|
|
44
|
+
|
|
45
|
+
[aggregates.purchase]
|
|
46
|
+
models = ["bookshop.Purchase", "bookshop.PurchaseLine"]
|
|
42
47
|
```
|
|
43
48
|
|
|
44
49
|
Models are written as `app_label.Model`. Models not listed in any aggregate are
|
|
@@ -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.7.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"
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/config.py
RENAMED
|
@@ -62,13 +62,41 @@ def _parse_aggregates(*, data: dict[str, Any], path: Path) -> dict[str, str]:
|
|
|
62
62
|
Model labels are lower-cased ("app_label.modelname") for case-insensitive
|
|
63
63
|
matching.
|
|
64
64
|
"""
|
|
65
|
+
aggregate_definitions = data.get("aggregates", {})
|
|
66
|
+
if not isinstance(aggregate_definitions, dict):
|
|
67
|
+
raise BoundariesConfigError(
|
|
68
|
+
f"{path}: define aggregates as named sections, for example "
|
|
69
|
+
"[aggregates.order] with models = [...]"
|
|
70
|
+
)
|
|
71
|
+
|
|
65
72
|
aggregates_by_model: dict[str, str] = {}
|
|
66
|
-
for aggregate,
|
|
67
|
-
if isinstance(
|
|
68
|
-
|
|
73
|
+
for aggregate, definition in aggregate_definitions.items():
|
|
74
|
+
if not isinstance(definition, dict):
|
|
75
|
+
raise BoundariesConfigError(
|
|
76
|
+
f"{path}: aggregate '{aggregate}' must define models in its own "
|
|
77
|
+
"section: "
|
|
78
|
+
f"[aggregates.{aggregate}] with models = [...]"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
unknown_fields = set(definition) - {"models"}
|
|
82
|
+
if unknown_fields:
|
|
83
|
+
fields = ", ".join(sorted(unknown_fields))
|
|
84
|
+
raise BoundariesConfigError(
|
|
85
|
+
f"{path}: aggregate '{aggregate}' has unknown field(s): {fields}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if "models" not in definition:
|
|
89
|
+
raise BoundariesConfigError(
|
|
90
|
+
f"{path}: aggregate '{aggregate}' is missing required 'models'"
|
|
91
|
+
)
|
|
92
|
+
members = definition["models"]
|
|
69
93
|
if not isinstance(members, list):
|
|
70
94
|
raise BoundariesConfigError(
|
|
71
|
-
f"{path}: aggregate '{aggregate}' must be a list
|
|
95
|
+
f"{path}: aggregate '{aggregate}' models must be a list"
|
|
96
|
+
)
|
|
97
|
+
if not members:
|
|
98
|
+
raise BoundariesConfigError(
|
|
99
|
+
f"{path}: aggregate '{aggregate}' models must not be empty"
|
|
72
100
|
)
|
|
73
101
|
for label in members:
|
|
74
102
|
if not isinstance(label, str):
|
|
@@ -90,7 +118,9 @@ def _parse_file_globs(
|
|
|
90
118
|
"""Read ``[allow]`` and ``[ignore] files`` into a list of glob patterns."""
|
|
91
119
|
section_data = data.get(section_name, {})
|
|
92
120
|
if not isinstance(section_data, dict):
|
|
93
|
-
raise BoundariesConfigError(
|
|
121
|
+
raise BoundariesConfigError(
|
|
122
|
+
f"{path}: [{section_name}] must be a section with a 'files' list"
|
|
123
|
+
)
|
|
94
124
|
|
|
95
125
|
files = section_data.get("files", [])
|
|
96
126
|
if not isinstance(files, list):
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/report.py
RENAMED
|
@@ -88,8 +88,8 @@ def report_stale_ignores(
|
|
|
88
88
|
return
|
|
89
89
|
terminalreporter.section("orm-boundaries: stale ignores", yellow=True, bold=True)
|
|
90
90
|
terminalreporter.write_line(
|
|
91
|
-
"These [ignore] entries
|
|
92
|
-
f"
|
|
91
|
+
"These [ignore] entries matched files that ran without crossing a "
|
|
92
|
+
f"boundary. Remove them from {CONFIG_FILE_NAME}:",
|
|
93
93
|
yellow=True,
|
|
94
94
|
)
|
|
95
95
|
for pattern in stale:
|
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/__init__.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/allows.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/callstack.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/crossings.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/guard.py
RENAMED
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/ignores.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/plugin.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytest_orm_boundaries-0.6.0 → pytest_orm_boundaries-0.7.0}/src/pytest_orm_boundaries/sql_parsing.py
RENAMED
|
File without changes
|