mongo-pipebuilder 0.3.1__tar.gz → 0.5.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.
- mongo_pipebuilder-0.5.0/MANIFEST.in +3 -0
- {mongo_pipebuilder-0.3.1/src/mongo_pipebuilder.egg-info → mongo_pipebuilder-0.5.0}/PKG-INFO +88 -6
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/README.md +85 -1
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/pyproject.toml +48 -8
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/src/mongo_pipebuilder/__init__.py +1 -1
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/src/mongo_pipebuilder/builder.py +304 -140
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0/src/mongo_pipebuilder.egg-info}/PKG-INFO +88 -6
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/src/mongo_pipebuilder.egg-info/SOURCES.txt +5 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/tests/test_builder.py +9 -10
- mongo_pipebuilder-0.5.0/tests/test_builder_add_stages.py +95 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/tests/test_builder_debug.py +51 -50
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/tests/test_builder_insert.py +22 -21
- mongo_pipebuilder-0.5.0/tests/test_builder_lookup_let.py +167 -0
- mongo_pipebuilder-0.5.0/tests/test_builder_match_expr.py +69 -0
- mongo_pipebuilder-0.5.0/tests/test_builder_union_with.py +95 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/tests/test_builder_validation.py +13 -14
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/tests/test_builder_validation_existing.py +2 -1
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/tests/test_builder_validation_new.py +1 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/LICENSE +0 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/setup.cfg +0 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/src/mongo_pipebuilder.egg-info/dependency_links.txt +0 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/src/mongo_pipebuilder.egg-info/requires.txt +0 -0
- {mongo_pipebuilder-0.3.1 → mongo_pipebuilder-0.5.0}/src/mongo_pipebuilder.egg-info/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mongo-pipebuilder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Type-safe, fluent MongoDB aggregation pipeline builder
|
|
5
5
|
Author-email: seligoroff <seligoroff@gmail.com>
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/seligoroff/mongo-pipebuilder
|
|
8
8
|
Project-URL: Documentation, https://github.com/seligoroff/mongo-pipebuilder#readme
|
|
9
9
|
Project-URL: Repository, https://github.com/seligoroff/mongo-pipebuilder
|
|
@@ -11,16 +11,14 @@ Project-URL: Issues, https://github.com/seligoroff/mongo-pipebuilder/issues
|
|
|
11
11
|
Keywords: mongodb,aggregation,pipeline,builder,query
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
14
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
19
|
Classifier: Topic :: Database
|
|
22
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.9
|
|
24
22
|
Description-Content-Type: text/markdown
|
|
25
23
|
License-File: LICENSE
|
|
26
24
|
Requires-Dist: typing_extensions>=4.0.0; python_version < "3.11"
|
|
@@ -29,7 +27,7 @@ Dynamic: license-file
|
|
|
29
27
|
# mongo-pipebuilder
|
|
30
28
|
|
|
31
29
|
[](https://badge.fury.io/py/mongo-pipebuilder)
|
|
32
|
-
[](https://www.python.org/downloads/)
|
|
33
31
|
[](https://opensource.org/licenses/MIT)
|
|
34
32
|
[](https://github.com/psf/black)
|
|
35
33
|
[](https://github.com/seligoroff/mongo-pipebuilder)
|
|
@@ -98,6 +96,15 @@ Adds a `$match` stage to filter documents.
|
|
|
98
96
|
.match({"status": "active", "age": {"$gte": 18}})
|
|
99
97
|
```
|
|
100
98
|
|
|
99
|
+
##### `match_expr(expr: Dict[str, Any]) -> Self`
|
|
100
|
+
|
|
101
|
+
Adds a `$match` stage with an `$expr` condition (expression-based filter; useful for comparing fields or using variables from `let` in subpipelines).
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
.match_expr({"$eq": ["$id", "$$teamId"]})
|
|
105
|
+
.match_expr({"$and": [{"$gte": ["$field", "$other"]}, {"$lte": ["$score", 100]}]})
|
|
106
|
+
```
|
|
107
|
+
|
|
101
108
|
##### `lookup(from_collection: str, local_field: str, foreign_field: str, as_field: str, pipeline: Optional[List[Dict[str, Any]]] = None) -> Self`
|
|
102
109
|
|
|
103
110
|
Adds a `$lookup` stage to join with another collection.
|
|
@@ -112,6 +119,43 @@ Adds a `$lookup` stage to join with another collection.
|
|
|
112
119
|
)
|
|
113
120
|
```
|
|
114
121
|
|
|
122
|
+
##### `lookup_let(from_collection: str, let: Dict[str, Any], pipeline: Union[List[Dict[str, Any]], PipelineBuilder], as_field: str) -> Self`
|
|
123
|
+
|
|
124
|
+
Adds a `$lookup` stage with `let` and `pipeline` (join by expression; variables from the current document are available in the subpipeline as `$$var`). Use this when the join condition is an expression (e.g. `$expr`) rather than equality of two fields.
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# With list of stages
|
|
128
|
+
.lookup_let(
|
|
129
|
+
from_collection="teams",
|
|
130
|
+
let={"teamId": "$idTeam"},
|
|
131
|
+
pipeline=[
|
|
132
|
+
{"$match": {"$expr": {"$eq": ["$_id", "$$teamId"]}}},
|
|
133
|
+
{"$project": {"name": 1, "_id": 0}}
|
|
134
|
+
],
|
|
135
|
+
as_field="team"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# With PipelineBuilder for the subpipeline (optionally using match_expr)
|
|
139
|
+
sub = PipelineBuilder().match_expr({"$eq": ["$_id", "$$teamId"]}).project({"name": 1, "_id": 0})
|
|
140
|
+
.lookup_let("teams", {"teamId": "$idTeam"}, sub, as_field="team")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
##### `union_with(coll: str, pipeline: Optional[Union[List[Dict[str, Any]], PipelineBuilder]] = None) -> Self`
|
|
144
|
+
|
|
145
|
+
Adds a `$unionWith` stage to combine documents from the current pipeline with documents from another collection. Optionally runs a subpipeline on the other collection before merging.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
# Union with another collection (no subpipeline)
|
|
149
|
+
.union_with("other_coll")
|
|
150
|
+
|
|
151
|
+
# With subpipeline as list of stages
|
|
152
|
+
.union_with("logs", [{"$match": {"level": "error"}}, {"$limit": 100}])
|
|
153
|
+
|
|
154
|
+
# With PipelineBuilder for the subpipeline
|
|
155
|
+
sub = PipelineBuilder().match({"source": "individual"}).project({"name": 1})
|
|
156
|
+
.union_with("sso_individual_statistics", sub)
|
|
157
|
+
```
|
|
158
|
+
|
|
115
159
|
##### `add_fields(fields: Dict[str, Any]) -> Self`
|
|
116
160
|
|
|
117
161
|
Adds a `$addFields` stage to add or modify fields.
|
|
@@ -237,6 +281,19 @@ Adds a custom stage for advanced use cases.
|
|
|
237
281
|
}})
|
|
238
282
|
```
|
|
239
283
|
|
|
284
|
+
##### `add_stages(stages: Iterable[Dict[str, Any]]) -> Self`
|
|
285
|
+
|
|
286
|
+
Adds multiple stages at once (e.g. a subpipeline from another builder). Empty dicts are skipped. Useful to avoid loops when inserting a ready-made list of stages.
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
# From a list
|
|
290
|
+
.add_stages([{"$match": {"level": "error"}}, {"$limit": 100}])
|
|
291
|
+
|
|
292
|
+
# From another builder
|
|
293
|
+
sub = PipelineBuilder().match({"source": "api"}).project({"name": 1})
|
|
294
|
+
.add_stages(sub.build())
|
|
295
|
+
```
|
|
296
|
+
|
|
240
297
|
##### `prepend(stage: Dict[str, Any]) -> Self`
|
|
241
298
|
|
|
242
299
|
Adds a stage at the beginning of the pipeline.
|
|
@@ -411,6 +468,31 @@ pipeline = (
|
|
|
411
468
|
)
|
|
412
469
|
```
|
|
413
470
|
|
|
471
|
+
### Lookup by expression (lookup_let)
|
|
472
|
+
|
|
473
|
+
When the join condition is an expression (e.g. `$expr`) rather than matching two fields, use `lookup_let`. The subpipeline can be built with `match_expr()`:
|
|
474
|
+
|
|
475
|
+
```python
|
|
476
|
+
sub = (
|
|
477
|
+
PipelineBuilder()
|
|
478
|
+
.match_expr({"$eq": ["$_id", "$$teamId"]})
|
|
479
|
+
.project({"name": 1, "slug": 1, "_id": 0})
|
|
480
|
+
)
|
|
481
|
+
pipeline = (
|
|
482
|
+
PipelineBuilder()
|
|
483
|
+
.match({"status": "active"})
|
|
484
|
+
.lookup_let(
|
|
485
|
+
from_collection="teams",
|
|
486
|
+
let={"teamId": "$idTeam"},
|
|
487
|
+
pipeline=sub,
|
|
488
|
+
as_field="team"
|
|
489
|
+
)
|
|
490
|
+
.unwind("team", preserve_null_and_empty_arrays=True)
|
|
491
|
+
.project({"title": 1, "teamName": "$team.name"})
|
|
492
|
+
.build()
|
|
493
|
+
)
|
|
494
|
+
```
|
|
495
|
+
|
|
414
496
|
### Aggregation with Grouping
|
|
415
497
|
|
|
416
498
|
```python
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# mongo-pipebuilder
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/py/mongo-pipebuilder)
|
|
4
|
-
[](https://www.python.org/downloads/)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://github.com/psf/black)
|
|
7
7
|
[](https://github.com/seligoroff/mongo-pipebuilder)
|
|
@@ -70,6 +70,15 @@ Adds a `$match` stage to filter documents.
|
|
|
70
70
|
.match({"status": "active", "age": {"$gte": 18}})
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
##### `match_expr(expr: Dict[str, Any]) -> Self`
|
|
74
|
+
|
|
75
|
+
Adds a `$match` stage with an `$expr` condition (expression-based filter; useful for comparing fields or using variables from `let` in subpipelines).
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
.match_expr({"$eq": ["$id", "$$teamId"]})
|
|
79
|
+
.match_expr({"$and": [{"$gte": ["$field", "$other"]}, {"$lte": ["$score", 100]}]})
|
|
80
|
+
```
|
|
81
|
+
|
|
73
82
|
##### `lookup(from_collection: str, local_field: str, foreign_field: str, as_field: str, pipeline: Optional[List[Dict[str, Any]]] = None) -> Self`
|
|
74
83
|
|
|
75
84
|
Adds a `$lookup` stage to join with another collection.
|
|
@@ -84,6 +93,43 @@ Adds a `$lookup` stage to join with another collection.
|
|
|
84
93
|
)
|
|
85
94
|
```
|
|
86
95
|
|
|
96
|
+
##### `lookup_let(from_collection: str, let: Dict[str, Any], pipeline: Union[List[Dict[str, Any]], PipelineBuilder], as_field: str) -> Self`
|
|
97
|
+
|
|
98
|
+
Adds a `$lookup` stage with `let` and `pipeline` (join by expression; variables from the current document are available in the subpipeline as `$$var`). Use this when the join condition is an expression (e.g. `$expr`) rather than equality of two fields.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
# With list of stages
|
|
102
|
+
.lookup_let(
|
|
103
|
+
from_collection="teams",
|
|
104
|
+
let={"teamId": "$idTeam"},
|
|
105
|
+
pipeline=[
|
|
106
|
+
{"$match": {"$expr": {"$eq": ["$_id", "$$teamId"]}}},
|
|
107
|
+
{"$project": {"name": 1, "_id": 0}}
|
|
108
|
+
],
|
|
109
|
+
as_field="team"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# With PipelineBuilder for the subpipeline (optionally using match_expr)
|
|
113
|
+
sub = PipelineBuilder().match_expr({"$eq": ["$_id", "$$teamId"]}).project({"name": 1, "_id": 0})
|
|
114
|
+
.lookup_let("teams", {"teamId": "$idTeam"}, sub, as_field="team")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
##### `union_with(coll: str, pipeline: Optional[Union[List[Dict[str, Any]], PipelineBuilder]] = None) -> Self`
|
|
118
|
+
|
|
119
|
+
Adds a `$unionWith` stage to combine documents from the current pipeline with documents from another collection. Optionally runs a subpipeline on the other collection before merging.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
# Union with another collection (no subpipeline)
|
|
123
|
+
.union_with("other_coll")
|
|
124
|
+
|
|
125
|
+
# With subpipeline as list of stages
|
|
126
|
+
.union_with("logs", [{"$match": {"level": "error"}}, {"$limit": 100}])
|
|
127
|
+
|
|
128
|
+
# With PipelineBuilder for the subpipeline
|
|
129
|
+
sub = PipelineBuilder().match({"source": "individual"}).project({"name": 1})
|
|
130
|
+
.union_with("sso_individual_statistics", sub)
|
|
131
|
+
```
|
|
132
|
+
|
|
87
133
|
##### `add_fields(fields: Dict[str, Any]) -> Self`
|
|
88
134
|
|
|
89
135
|
Adds a `$addFields` stage to add or modify fields.
|
|
@@ -209,6 +255,19 @@ Adds a custom stage for advanced use cases.
|
|
|
209
255
|
}})
|
|
210
256
|
```
|
|
211
257
|
|
|
258
|
+
##### `add_stages(stages: Iterable[Dict[str, Any]]) -> Self`
|
|
259
|
+
|
|
260
|
+
Adds multiple stages at once (e.g. a subpipeline from another builder). Empty dicts are skipped. Useful to avoid loops when inserting a ready-made list of stages.
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
# From a list
|
|
264
|
+
.add_stages([{"$match": {"level": "error"}}, {"$limit": 100}])
|
|
265
|
+
|
|
266
|
+
# From another builder
|
|
267
|
+
sub = PipelineBuilder().match({"source": "api"}).project({"name": 1})
|
|
268
|
+
.add_stages(sub.build())
|
|
269
|
+
```
|
|
270
|
+
|
|
212
271
|
##### `prepend(stage: Dict[str, Any]) -> Self`
|
|
213
272
|
|
|
214
273
|
Adds a stage at the beginning of the pipeline.
|
|
@@ -383,6 +442,31 @@ pipeline = (
|
|
|
383
442
|
)
|
|
384
443
|
```
|
|
385
444
|
|
|
445
|
+
### Lookup by expression (lookup_let)
|
|
446
|
+
|
|
447
|
+
When the join condition is an expression (e.g. `$expr`) rather than matching two fields, use `lookup_let`. The subpipeline can be built with `match_expr()`:
|
|
448
|
+
|
|
449
|
+
```python
|
|
450
|
+
sub = (
|
|
451
|
+
PipelineBuilder()
|
|
452
|
+
.match_expr({"$eq": ["$_id", "$$teamId"]})
|
|
453
|
+
.project({"name": 1, "slug": 1, "_id": 0})
|
|
454
|
+
)
|
|
455
|
+
pipeline = (
|
|
456
|
+
PipelineBuilder()
|
|
457
|
+
.match({"status": "active"})
|
|
458
|
+
.lookup_let(
|
|
459
|
+
from_collection="teams",
|
|
460
|
+
let={"teamId": "$idTeam"},
|
|
461
|
+
pipeline=sub,
|
|
462
|
+
as_field="team"
|
|
463
|
+
)
|
|
464
|
+
.unwind("team", preserve_null_and_empty_arrays=True)
|
|
465
|
+
.project({"title": 1, "teamName": "$team.name"})
|
|
466
|
+
.build()
|
|
467
|
+
)
|
|
468
|
+
```
|
|
469
|
+
|
|
386
470
|
### Aggregation with Grouping
|
|
387
471
|
|
|
388
472
|
```python
|
|
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mongo-pipebuilder"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "Type-safe, fluent MongoDB aggregation pipeline builder"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
11
|
dependencies = [
|
|
12
12
|
"typing_extensions>=4.0.0; python_version<'3.11'",
|
|
13
13
|
]
|
|
14
|
-
license =
|
|
14
|
+
license = "MIT"
|
|
15
15
|
authors = [
|
|
16
16
|
{name = "seligoroff", email = "seligoroff@gmail.com"}
|
|
17
17
|
]
|
|
@@ -19,9 +19,7 @@ keywords = ["mongodb", "aggregation", "pipeline", "builder", "query"]
|
|
|
19
19
|
classifiers = [
|
|
20
20
|
"Development Status :: 3 - Alpha",
|
|
21
21
|
"Intended Audience :: Developers",
|
|
22
|
-
"License :: OSI Approved :: MIT License",
|
|
23
22
|
"Programming Language :: Python :: 3",
|
|
24
|
-
"Programming Language :: Python :: 3.8",
|
|
25
23
|
"Programming Language :: Python :: 3.9",
|
|
26
24
|
"Programming Language :: Python :: 3.10",
|
|
27
25
|
"Programming Language :: Python :: 3.11",
|
|
@@ -51,12 +49,13 @@ addopts = [
|
|
|
51
49
|
"--cov=src/mongo_pipebuilder",
|
|
52
50
|
"--cov-report=term-missing",
|
|
53
51
|
"--cov-report=html:tests/htmlcov",
|
|
54
|
-
"--cov-report=json:coverage.json",
|
|
55
|
-
"--cov-report=xml:coverage.xml",
|
|
52
|
+
"--cov-report=json:tests/coverage.json",
|
|
53
|
+
"--cov-report=xml:tests/coverage.xml",
|
|
56
54
|
"--cov-branch",
|
|
57
55
|
]
|
|
58
56
|
|
|
59
57
|
[tool.coverage.run]
|
|
58
|
+
data_file = "tests/.coverage"
|
|
60
59
|
source = ["src/mongo_pipebuilder"]
|
|
61
60
|
omit = [
|
|
62
61
|
"*/tests/*",
|
|
@@ -84,7 +83,7 @@ skip_empty = true
|
|
|
84
83
|
directory = "tests/htmlcov"
|
|
85
84
|
|
|
86
85
|
[tool.mypy]
|
|
87
|
-
python_version = "3.
|
|
86
|
+
python_version = "3.9"
|
|
88
87
|
warn_return_any = true
|
|
89
88
|
warn_unused_configs = true
|
|
90
89
|
disallow_untyped_defs = false
|
|
@@ -99,3 +98,44 @@ warn_no_return = true
|
|
|
99
98
|
module = "tests.*"
|
|
100
99
|
disallow_untyped_defs = false
|
|
101
100
|
|
|
101
|
+
[tool.ruff]
|
|
102
|
+
line-length = 110
|
|
103
|
+
target-version = "py311"
|
|
104
|
+
# В Ruff лучше использовать .gitignore, но если нужно строго как было:
|
|
105
|
+
#respect-gitignore = false
|
|
106
|
+
#extend-exclude = ["venv", "deprecated"]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint]
|
|
109
|
+
# E, F — база (Flake8), B — Bugbear (ошибки логики), I — Isort (импорты)
|
|
110
|
+
select = ["E", "F", "W", "B", "C901", "I", "Q", "T20", "COM"]
|
|
111
|
+
ignore = [
|
|
112
|
+
"B008", # Аргументы-функции в дефолтных значениях (часто нужно для FastAPI Depends)
|
|
113
|
+
"E266", # Слишком много # в комментариях
|
|
114
|
+
"E712", # Сравнение с True через == (иногда нужно в SQLAlchemy)
|
|
115
|
+
"COM812", # Конфликт с форматтером (запятые)
|
|
116
|
+
"COM819", # Trailing comma в type hints
|
|
117
|
+
"E203", # Пробел перед двоеточием (совместимость с Black)
|
|
118
|
+
"Q003", # Кавычки в f-строках
|
|
119
|
+
"PT006", # Типы параметров pytest
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
[tool.ruff.lint.per-file-ignores]
|
|
123
|
+
# Игнорируем специфичные ошибки в тестах, скриптах, примерах и инициализации
|
|
124
|
+
"tests/*" = ["T201"]
|
|
125
|
+
"examples/*" = ["T201"]
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
[tool.ruff.lint.mccabe]
|
|
129
|
+
max-complexity = 12
|
|
130
|
+
|
|
131
|
+
[tool.ruff.lint.isort]
|
|
132
|
+
# Автоматически определяет внутренние модули, чтобы не мешать их с pip-пакетами
|
|
133
|
+
known-first-party = [
|
|
134
|
+
"api", "cli", "constants", "core", "helpers",
|
|
135
|
+
"infrastructure", "schemas", "scripts", "services",
|
|
136
|
+
"startup", "tasks", "tests"
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
[tool.ruff.format]
|
|
140
|
+
quote-style = "double"
|
|
141
|
+
indent-style = "space"
|