querymodelling 0.0.1__tar.gz → 0.0.2a0__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.
- {querymodelling-0.0.1/querymodelling.egg-info → querymodelling-0.0.2a0}/PKG-INFO +9 -1
- querymodelling-0.0.2a0/README.md +10 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/pyproject.toml +1 -1
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling/__version__.py +1 -1
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling/base.py +28 -14
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling/fields.py +4 -2
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling/model.py +0 -1
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling/pydantic.py +0 -3
- querymodelling-0.0.2a0/querymodelling/sql.py +143 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0/querymodelling.egg-info}/PKG-INFO +9 -1
- querymodelling-0.0.1/README.md +0 -2
- querymodelling-0.0.1/querymodelling/sql.py +0 -111
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/AUTHORS.rst +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/LICENSE +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling/__init__.py +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling.egg-info/SOURCES.txt +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling.egg-info/dependency_links.txt +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling.egg-info/requires.txt +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling.egg-info/top_level.txt +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/setup.cfg +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/setup.py +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/tests/__init__.py +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/tests/__main__.py +0 -0
- {querymodelling-0.0.1 → querymodelling-0.0.2a0}/tests/basic_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: querymodelling
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2a0
|
|
4
4
|
Summary: build consistent api query models for fastapi
|
|
5
5
|
Author: George Haddad
|
|
6
6
|
Author-email: George Haddad <georgeh87@live.de>
|
|
@@ -215,3 +215,11 @@ Dynamic: author
|
|
|
215
215
|
|
|
216
216
|
# querymodelling
|
|
217
217
|
build consistent api query models for fastapi
|
|
218
|
+
|
|
219
|
+
## Requirements
|
|
220
|
+
At least you will need to have the pydantic package installed. Of course it make sense to have some kind of service supporting query models like fast api. Currently sql models are implemented - but feel free to create new ones.
|
|
221
|
+
|
|
222
|
+
## Installation
|
|
223
|
+
|
|
224
|
+
## Example
|
|
225
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# querymodelling
|
|
2
|
+
build consistent api query models for fastapi
|
|
3
|
+
|
|
4
|
+
## Requirements
|
|
5
|
+
At least you will need to have the pydantic package installed. Of course it make sense to have some kind of service supporting query models like fast api. Currently sql models are implemented - but feel free to create new ones.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from pydantic import BaseModel, create_model, Field
|
|
2
2
|
from pydantic.fields import FieldInfo
|
|
3
3
|
from typing import (
|
|
4
|
-
TypeVar, Literal, Type, Callable, Dict, Tuple, Any, get_origin, Optional,
|
|
4
|
+
TypeVar, Literal, Type, Callable, Dict, Tuple, Any, get_origin, Optional,
|
|
5
|
+
Union, get_args, Generator
|
|
5
6
|
)
|
|
6
7
|
|
|
7
8
|
from .model import PageQuery
|
|
@@ -21,7 +22,7 @@ def get_functions(model: BaseModel, function_type: str):
|
|
|
21
22
|
queries.append(function(getattr(model, name)))
|
|
22
23
|
return queries
|
|
23
24
|
|
|
24
|
-
A = TypeVar("A"
|
|
25
|
+
A = TypeVar("A")
|
|
25
26
|
|
|
26
27
|
def optional_fields(
|
|
27
28
|
base_model: BaseModel,
|
|
@@ -47,10 +48,8 @@ def optional_fields(
|
|
|
47
48
|
return fields
|
|
48
49
|
|
|
49
50
|
T = TypeVar("T", bound=BaseModel)
|
|
50
|
-
Ts = TypeVarTuple("Ts")
|
|
51
51
|
C = TypeVar("C", bound=Union[PageQuery, BaseModel])
|
|
52
52
|
|
|
53
|
-
|
|
54
53
|
def parse_field(input_field: FieldInfo) -> FieldInfo:
|
|
55
54
|
data = {
|
|
56
55
|
key: getattr(input_field, key)
|
|
@@ -61,21 +60,36 @@ def parse_field(input_field: FieldInfo) -> FieldInfo:
|
|
|
61
60
|
return Field(**data)
|
|
62
61
|
|
|
63
62
|
def AutoQueryModel(
|
|
64
|
-
base_models: Type[
|
|
63
|
+
base_models: Type[T] | list[Type[T]],
|
|
65
64
|
base_query_models: Type[C] | list[Type[C]],
|
|
66
|
-
callback: Callable[
|
|
65
|
+
callback: Callable[
|
|
66
|
+
[type, str, any, FieldInfo],
|
|
67
|
+
Generator[Tuple[Type, str, Any, FieldInfo, Any], None, None]
|
|
68
|
+
],
|
|
67
69
|
exclude_fields: list[str] = None,
|
|
68
70
|
include_fields: list[str] = None
|
|
69
71
|
) -> Type[A]:
|
|
70
|
-
"""
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
"""Automatic generates a query model based on the fields of the base query
|
|
73
|
+
models. The newly generated model will have the same fields as the base
|
|
74
|
+
query models, but with the option to modify the fields using the callback
|
|
75
|
+
function or using the exclude- and include- fields parameters. The
|
|
76
|
+
callback function will be called for each field of the base query models
|
|
77
|
+
and should return a tuple with the field name, the field info and the
|
|
78
|
+
annotation of the field. The exclude- and include- fields parameters can
|
|
79
|
+
be used to exclude or include specific fields from the base query models.
|
|
80
|
+
On the other hand the newly generated model will inherit from the defined
|
|
81
|
+
base models.
|
|
82
|
+
|
|
83
|
+
:param base_models: The base models to inherit from.
|
|
73
84
|
:type base_models: Type[A] | list[Type[A]]
|
|
74
|
-
:param base_query_models:
|
|
85
|
+
:param base_query_models: The base query models to generate the query
|
|
86
|
+
model from.
|
|
75
87
|
:type base_query_models: Type[C] | list[Type[C]]
|
|
76
|
-
:param callback:
|
|
77
|
-
|
|
78
|
-
:
|
|
88
|
+
:param callback: The callback function to modify the fields of the base
|
|
89
|
+
query models.
|
|
90
|
+
:type callback: Callable[[type, str, any, FieldInfo],
|
|
91
|
+
Generator[Tuple[Type, str, Any, FieldInfo, Any], None, None]]
|
|
92
|
+
:param exclude_fields: , defaults to None
|
|
79
93
|
:type exclude_fields: list[str], optional
|
|
80
94
|
:param include_fields: _description_, defaults to None
|
|
81
95
|
:type include_fields: list[str], optional
|
|
@@ -121,4 +135,4 @@ def AutoQueryModel(
|
|
|
121
135
|
)
|
|
122
136
|
return model
|
|
123
137
|
|
|
124
|
-
DefaultSort = Literal["asc", "desc"]
|
|
138
|
+
DefaultSort = Literal["asc", "desc"]
|
|
@@ -5,18 +5,21 @@ from typing import TypeVar, ParamSpec, Callable, Concatenate
|
|
|
5
5
|
T = TypeVar("T", bound=BaseModel)
|
|
6
6
|
PK = ParamSpec("PK")
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
def Field(BaseField: Callable[PK, T]):
|
|
10
9
|
def field_wrapper(
|
|
11
10
|
*args,
|
|
12
11
|
query_function = None,
|
|
13
12
|
sort_function = None,
|
|
14
13
|
query_type: str = None,
|
|
14
|
+
json_schema_extra: dict = None,
|
|
15
15
|
**kwargs
|
|
16
16
|
):
|
|
17
17
|
field_info = BaseField(
|
|
18
18
|
*args,
|
|
19
19
|
query_type=query_type,
|
|
20
|
+
json_schema_extra=(json_schema_extra or {}) | {
|
|
21
|
+
"query.type": query_type
|
|
22
|
+
},
|
|
20
23
|
**kwargs,
|
|
21
24
|
)
|
|
22
25
|
if query_function:
|
|
@@ -24,7 +27,6 @@ def Field(BaseField: Callable[PK, T]):
|
|
|
24
27
|
if sort_function:
|
|
25
28
|
field_info.metadata.append(("sort_function", sort_function))
|
|
26
29
|
return field_info
|
|
27
|
-
|
|
28
30
|
return field_wrapper
|
|
29
31
|
|
|
30
32
|
def QueryField(BaseField: Callable[PK, T]) -> Callable[
|
|
@@ -2,10 +2,7 @@ from pydantic import Field
|
|
|
2
2
|
|
|
3
3
|
from .fields import QueryField as BaseQueryField
|
|
4
4
|
from .fields import SortField as BaseSortField
|
|
5
|
-
from .sql import ExtendedTextSearch as BaseExtendedSqlTextSearch
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
QueryField = BaseQueryField(Field)
|
|
9
8
|
SortField = BaseSortField(Field)
|
|
10
|
-
|
|
11
|
-
ExtendedSqlTextSearch = BaseExtendedSqlTextSearch(Field)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from sqlmodel import Session, select, func
|
|
3
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
4
|
+
from typing import TypeVar, Sequence, Type, Callable, ParamSpec
|
|
5
|
+
from pydantic import AliasChoices
|
|
6
|
+
|
|
7
|
+
from .base import get_functions, DefaultSort
|
|
8
|
+
from .fields import QueryField, SortField
|
|
9
|
+
from .model import PageQuery
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T")
|
|
13
|
+
PK = ParamSpec("PK")
|
|
14
|
+
Q = TypeVar("Q", bound=PageQuery)
|
|
15
|
+
|
|
16
|
+
def sortable_by(field):
|
|
17
|
+
def wrapper(order: DefaultSort):
|
|
18
|
+
if order == "desc":
|
|
19
|
+
return field.desc()
|
|
20
|
+
if order == "asc":
|
|
21
|
+
return field.asc()
|
|
22
|
+
return wrapper
|
|
23
|
+
|
|
24
|
+
def retrieve_entries(
|
|
25
|
+
query: Q,
|
|
26
|
+
session: Session,
|
|
27
|
+
t: Type[T],
|
|
28
|
+
t_index: InstrumentedAttribute
|
|
29
|
+
) -> tuple[int, Sequence[T]]:
|
|
30
|
+
search_clause = get_functions(query, "query")
|
|
31
|
+
order_clause = get_functions(query, "sort")
|
|
32
|
+
total_elements = session.exec(select(func.count()).where(
|
|
33
|
+
*search_clause).select_from(t)).first()
|
|
34
|
+
|
|
35
|
+
sub_statement = select(t_index)
|
|
36
|
+
if search_clause:
|
|
37
|
+
sub_statement = sub_statement.where(*search_clause)
|
|
38
|
+
if order_clause:
|
|
39
|
+
sub_statement = sub_statement.order_by(*order_clause)
|
|
40
|
+
sub_statement = sub_statement.limit(query.size).offset(
|
|
41
|
+
query.page * query.size)
|
|
42
|
+
sub_query = sub_statement.subquery()
|
|
43
|
+
sub_query_id = sub_query.c.__getattr__(t_index.key)
|
|
44
|
+
|
|
45
|
+
statement = select(t).join(
|
|
46
|
+
sub_query, t_index == sub_query_id)
|
|
47
|
+
|
|
48
|
+
return total_elements, session.exec(statement).all()
|
|
49
|
+
|
|
50
|
+
def create_query_fields(
|
|
51
|
+
base_field: any,
|
|
52
|
+
field_name: str,
|
|
53
|
+
annotation: any,
|
|
54
|
+
operator_mapping: dict[str, Callable],
|
|
55
|
+
json_schema_extra: dict
|
|
56
|
+
):
|
|
57
|
+
for operator, operator_function in operator_mapping.items():
|
|
58
|
+
validation_alias = None
|
|
59
|
+
alias = None
|
|
60
|
+
if operator is None:
|
|
61
|
+
name = field_name
|
|
62
|
+
else:
|
|
63
|
+
name = f"{field_name}_{operator}"
|
|
64
|
+
alias = f"{field_name}.{operator}"
|
|
65
|
+
validation_alias = AliasChoices(name, alias)
|
|
66
|
+
yield (
|
|
67
|
+
name,
|
|
68
|
+
QueryField(base_field)(
|
|
69
|
+
operator_function,
|
|
70
|
+
alias=alias,
|
|
71
|
+
validation_alias=validation_alias,
|
|
72
|
+
default=None,
|
|
73
|
+
json_schema_extra=json_schema_extra | {
|
|
74
|
+
"query.backend": "sql",
|
|
75
|
+
"query.operator": operator
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
annotation
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def create_callback(
|
|
82
|
+
base_field,
|
|
83
|
+
copy_field_properties: list[str] = None,
|
|
84
|
+
schema_extra: dict = None
|
|
85
|
+
):
|
|
86
|
+
def auto_create_callback(
|
|
87
|
+
source_type: type,
|
|
88
|
+
field_name: str,
|
|
89
|
+
field,
|
|
90
|
+
field_info,
|
|
91
|
+
annotation
|
|
92
|
+
):
|
|
93
|
+
if copy_field_properties is None and schema_extra is None:
|
|
94
|
+
json_schema_extra = field_info.json_schema_extra
|
|
95
|
+
json_schema_extra = schema_extra or {}
|
|
96
|
+
if copy_field_properties is not None:
|
|
97
|
+
for property_name in copy_field_properties:
|
|
98
|
+
json_schema_extra[property_name] = field_info[
|
|
99
|
+
property_name]
|
|
100
|
+
|
|
101
|
+
if annotation == str:
|
|
102
|
+
operator_mapping = {
|
|
103
|
+
None: lambda value: field == value,
|
|
104
|
+
"startswith": lambda value: field.like(f"{value}%"),
|
|
105
|
+
"endswith": lambda value: field.like(f"%{value}"),
|
|
106
|
+
"contains": lambda value: field.like(f"%{value}%")
|
|
107
|
+
}
|
|
108
|
+
yield from create_query_fields(
|
|
109
|
+
base_field,
|
|
110
|
+
field_name,
|
|
111
|
+
annotation,
|
|
112
|
+
operator_mapping,
|
|
113
|
+
json_schema_extra
|
|
114
|
+
)
|
|
115
|
+
elif annotation in (datetime, int):
|
|
116
|
+
operator_mapping = {
|
|
117
|
+
None: lambda value: field == value,
|
|
118
|
+
"from": lambda value: field >= value,
|
|
119
|
+
"to": lambda value: field <= value
|
|
120
|
+
}
|
|
121
|
+
yield from create_query_fields(
|
|
122
|
+
base_field,
|
|
123
|
+
field_name,
|
|
124
|
+
annotation,
|
|
125
|
+
operator_mapping,
|
|
126
|
+
json_schema_extra
|
|
127
|
+
)
|
|
128
|
+
sort_name = f"sort_{field_name}"
|
|
129
|
+
sort_name_dot = f"sort.{field_name}"
|
|
130
|
+
yield (
|
|
131
|
+
sort_name_dot,
|
|
132
|
+
SortField(base_field)(
|
|
133
|
+
sortable_by(source_type.__dict__[field_name]),
|
|
134
|
+
alias=sort_name_dot,
|
|
135
|
+
validation_alias=AliasChoices(sort_name, sort_name_dot),
|
|
136
|
+
default=None,
|
|
137
|
+
json_schema_extra=json_schema_extra | {
|
|
138
|
+
"query.backend": "sql"
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
DefaultSort
|
|
142
|
+
)
|
|
143
|
+
return auto_create_callback
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: querymodelling
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2a0
|
|
4
4
|
Summary: build consistent api query models for fastapi
|
|
5
5
|
Author: George Haddad
|
|
6
6
|
Author-email: George Haddad <georgeh87@live.de>
|
|
@@ -215,3 +215,11 @@ Dynamic: author
|
|
|
215
215
|
|
|
216
216
|
# querymodelling
|
|
217
217
|
build consistent api query models for fastapi
|
|
218
|
+
|
|
219
|
+
## Requirements
|
|
220
|
+
At least you will need to have the pydantic package installed. Of course it make sense to have some kind of service supporting query models like fast api. Currently sql models are implemented - but feel free to create new ones.
|
|
221
|
+
|
|
222
|
+
## Installation
|
|
223
|
+
|
|
224
|
+
## Example
|
|
225
|
+
|
querymodelling-0.0.1/README.md
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from sqlmodel import Session, select, func
|
|
3
|
-
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
4
|
-
from typing import TypeVar, Sequence, Type, Callable, Concatenate, ParamSpec
|
|
5
|
-
|
|
6
|
-
from .base import get_functions, DefaultSort
|
|
7
|
-
from .fields import QueryField, SortField
|
|
8
|
-
from .model import PageQuery
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
T = TypeVar("T")
|
|
12
|
-
PK = ParamSpec("PK")
|
|
13
|
-
Q = TypeVar("Q", bound=PageQuery)
|
|
14
|
-
|
|
15
|
-
def sortable_by(field):
|
|
16
|
-
def wrapper(order: DefaultSort):
|
|
17
|
-
if order == "desc":
|
|
18
|
-
return field.desc()
|
|
19
|
-
return wrapper
|
|
20
|
-
|
|
21
|
-
def ExtendedTextSearch(BaseField) -> Callable[
|
|
22
|
-
Concatenate[Callable, PK], T]:
|
|
23
|
-
def field_wrapper(field, *args, **kwargs):
|
|
24
|
-
def query(value):
|
|
25
|
-
if value.startswith("startswith:"):
|
|
26
|
-
return field.like(f"{value[11:]}%")
|
|
27
|
-
if value.startswith("endswith:"):
|
|
28
|
-
return field.like(f"%{value[9:]}")
|
|
29
|
-
if value.startswith("contains:"):
|
|
30
|
-
return field.like(f"%{value[9:]}%")
|
|
31
|
-
return field == value
|
|
32
|
-
return QueryField(BaseField)(
|
|
33
|
-
query,
|
|
34
|
-
*args,
|
|
35
|
-
pattern="^(?:(?:startswith:|endswith:|contains))?.+",
|
|
36
|
-
**kwargs
|
|
37
|
-
)
|
|
38
|
-
return field_wrapper
|
|
39
|
-
|
|
40
|
-
def retrieve_entries(
|
|
41
|
-
query: Q,
|
|
42
|
-
session: Session,
|
|
43
|
-
t: Type[T],
|
|
44
|
-
t_index: InstrumentedAttribute
|
|
45
|
-
) -> tuple[int, Sequence[T]]:
|
|
46
|
-
search_clause = get_functions(query, "query")
|
|
47
|
-
order_clause = get_functions(query, "sort")
|
|
48
|
-
total_elements = session.exec(select(func.count()).where(
|
|
49
|
-
*search_clause).select_from(t)).first()
|
|
50
|
-
|
|
51
|
-
sub_statement = select(t_index)
|
|
52
|
-
if search_clause:
|
|
53
|
-
sub_statement = sub_statement.where(*search_clause)
|
|
54
|
-
if order_clause:
|
|
55
|
-
sub_statement = sub_statement.order_by(*order_clause)
|
|
56
|
-
sub_statement = sub_statement.limit(query.size).offset(
|
|
57
|
-
query.page * query.size)
|
|
58
|
-
sub_query = sub_statement.subquery()
|
|
59
|
-
sub_query_id = sub_query.c.__getattr__(t_index.key)
|
|
60
|
-
|
|
61
|
-
statement = select(t).join(
|
|
62
|
-
sub_query, t_index == sub_query_id)
|
|
63
|
-
|
|
64
|
-
return total_elements, session.exec(statement).all()
|
|
65
|
-
|
|
66
|
-
def create_callback(base_field):
|
|
67
|
-
def auto_create_callback(
|
|
68
|
-
source_type: type,
|
|
69
|
-
field_name: str,
|
|
70
|
-
field,
|
|
71
|
-
field_info,
|
|
72
|
-
annotation
|
|
73
|
-
):
|
|
74
|
-
if annotation == str:
|
|
75
|
-
yield (
|
|
76
|
-
field_name,
|
|
77
|
-
ExtendedTextSearch(base_field)(
|
|
78
|
-
source_type.__dict__[field_name],
|
|
79
|
-
default=None
|
|
80
|
-
),
|
|
81
|
-
annotation
|
|
82
|
-
)
|
|
83
|
-
elif annotation in (datetime, int):
|
|
84
|
-
yield (
|
|
85
|
-
f"from_{field_name}",
|
|
86
|
-
QueryField(base_field)(
|
|
87
|
-
lambda value: source_type.__dict__[field_name] >= value,
|
|
88
|
-
alias=f"{field_name}.from",
|
|
89
|
-
default=None
|
|
90
|
-
),
|
|
91
|
-
annotation
|
|
92
|
-
)
|
|
93
|
-
yield (
|
|
94
|
-
f"to_{field_name}",
|
|
95
|
-
QueryField(base_field)(
|
|
96
|
-
lambda value: source_type.__dict__[field_name] <= value,
|
|
97
|
-
alias=f"{field_name}.to",
|
|
98
|
-
default=None
|
|
99
|
-
),
|
|
100
|
-
annotation
|
|
101
|
-
)
|
|
102
|
-
yield (
|
|
103
|
-
f"sort_{field_name}",
|
|
104
|
-
SortField(base_field)(
|
|
105
|
-
sortable_by(source_type.__dict__[field_name]),
|
|
106
|
-
alias=f"sort_{field_name}",
|
|
107
|
-
default=None
|
|
108
|
-
),
|
|
109
|
-
DefaultSort
|
|
110
|
-
)
|
|
111
|
-
return auto_create_callback
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{querymodelling-0.0.1 → querymodelling-0.0.2a0}/querymodelling.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|