sqlalchemyseed 1.0.5__tar.gz → 1.0.7__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.
- {sqlalchemyseed-1.0.5/src/sqlalchemyseed.egg-info → sqlalchemyseed-1.0.7}/PKG-INFO +65 -5
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/README.md +66 -2
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/pyproject.toml +1 -1
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/setup.cfg +3 -5
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/setup.py +4 -4
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/__init__.py +17 -0
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/attribute.py +70 -0
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/constants.py +4 -0
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/dynamic_seeder.py +4 -0
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/src/sqlalchemyseed/errors.py +4 -9
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/json.py +168 -0
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/loader.py +64 -0
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/seeder.py +316 -0
- sqlalchemyseed-1.0.7/src/sqlalchemyseed/util.py +114 -0
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/src/sqlalchemyseed/validator.py +1 -21
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7/src/sqlalchemyseed.egg-info}/PKG-INFO +65 -5
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/src/sqlalchemyseed.egg-info/SOURCES.txt +10 -2
- sqlalchemyseed-1.0.7/src/sqlalchemyseed.egg-info/requires.txt +4 -0
- sqlalchemyseed-1.0.7/tests/test_json.py +58 -0
- sqlalchemyseed-1.0.7/tests/test_loader.py +41 -0
- sqlalchemyseed-1.0.7/tests/test_seeder.py +596 -0
- sqlalchemyseed-1.0.7/tests/test_temp_seeder.py +10 -0
- sqlalchemyseed-1.0.7/tests/test_validator.py +87 -0
- sqlalchemyseed-1.0.5/src/sqlalchemyseed/__init__.py +0 -35
- sqlalchemyseed-1.0.5/src/sqlalchemyseed/class_registry.py +0 -75
- sqlalchemyseed-1.0.5/src/sqlalchemyseed/loader.py +0 -77
- sqlalchemyseed-1.0.5/src/sqlalchemyseed/seeder.py +0 -308
- sqlalchemyseed-1.0.5/src/sqlalchemyseed/util.py +0 -22
- sqlalchemyseed-1.0.5/src/sqlalchemyseed.egg-info/requires.txt +0 -8
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/LICENSE +0 -0
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/src/sqlalchemyseed/_future/__init__.py +0 -0
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/src/sqlalchemyseed/_future/seeder.py +0 -0
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/src/sqlalchemyseed.egg-info/dependency_links.txt +0 -0
- {sqlalchemyseed-1.0.5 → sqlalchemyseed-1.0.7}/src/sqlalchemyseed.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sqlalchemyseed
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: SQLAlchemy Seeder
|
|
5
5
|
Home-page: https://github.com/jedymatt/sqlalchemyseed
|
|
6
6
|
Author: Jedy Matt Tabasco
|
|
@@ -10,7 +10,6 @@ Project-URL: Documentation, https://sqlalchemyseed.readthedocs.io/
|
|
|
10
10
|
Project-URL: Source, https://github.com/jedymatt/sqlalchemyseed
|
|
11
11
|
Project-URL: Tracker, https://github.com/jedymatt/sqlalchemyseed/issues
|
|
12
12
|
Keywords: sqlalchemy,orm,seed,seeder,json,yaml
|
|
13
|
-
Platform: UNKNOWN
|
|
14
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.6
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.7
|
|
@@ -20,7 +19,6 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
20
19
|
Requires-Python: >=3.6
|
|
21
20
|
Description-Content-Type: text/markdown
|
|
22
21
|
Provides-Extra: yaml
|
|
23
|
-
Provides-Extra: docs
|
|
24
22
|
License-File: LICENSE
|
|
25
23
|
|
|
26
24
|
# sqlalchemyseed
|
|
@@ -28,7 +26,7 @@ License-File: LICENSE
|
|
|
28
26
|
[](https://pypi.org/project/sqlalchemyseed)
|
|
29
27
|
[](https://pypi.org/project/sqlalchemyseed)
|
|
30
28
|
[](https://github.com/jedymatt/sqlalchemyseed/blob/main/LICENSE)
|
|
31
|
-
[](https://github.com/jedymatt/sqlalchemyseed/actions/workflows/python-package.yml)
|
|
32
30
|
[](https://codeclimate.com/github/jedymatt/sqlalchemyseed/maintainability)
|
|
33
31
|
[](https://codecov.io/gh/jedymatt/sqlalchemyseed)
|
|
34
32
|
[](https://sqlalchemyseed.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -51,8 +49,9 @@ pip install sqlalchemyseed
|
|
|
51
49
|
|
|
52
50
|
## Quickstart
|
|
53
51
|
|
|
52
|
+
main.py
|
|
53
|
+
|
|
54
54
|
```python
|
|
55
|
-
# main.py
|
|
56
55
|
from sqlalchemyseed import load_entities_from_json
|
|
57
56
|
from sqlalchemyseed import Seeder
|
|
58
57
|
from db import session
|
|
@@ -70,8 +69,69 @@ seeder.seed(entities)
|
|
|
70
69
|
session.commit() # or seeder.session.commit()
|
|
71
70
|
```
|
|
72
71
|
|
|
72
|
+
data.json
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"model": "models.Person",
|
|
77
|
+
"data": [
|
|
78
|
+
{
|
|
79
|
+
"name": "John March",
|
|
80
|
+
"age": 23
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "Juan Dela Cruz",
|
|
84
|
+
"age": 21
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
73
90
|
## Documentation
|
|
74
91
|
|
|
75
92
|
<https://sqlalchemyseed.readthedocs.io/>
|
|
76
93
|
|
|
94
|
+
## Found Bug?
|
|
95
|
+
|
|
96
|
+
Report here in this link:
|
|
97
|
+
<https://github.com/jedymatt/sqlalchemyseed/issues>
|
|
98
|
+
|
|
99
|
+
## Want to contribute?
|
|
100
|
+
|
|
101
|
+
First, Clone this [repository](https://github.com/jedymatt/sqlalchemyseed).
|
|
102
|
+
|
|
103
|
+
### Install dev dependencies
|
|
104
|
+
|
|
105
|
+
Inside the folder, paste this in the terminal to install necessary dependencies:
|
|
106
|
+
|
|
107
|
+
```shell
|
|
108
|
+
pip install -r requirements.txt -r docs/requirements.txt
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Note: make sure you have the virtual environment and enabled, or if you are using vs code and docker then you can simply re-open this as container.
|
|
112
|
+
|
|
113
|
+
### Run tests
|
|
114
|
+
|
|
115
|
+
Before running tests, make sure that the package is installed as editable:
|
|
77
116
|
|
|
117
|
+
```shell
|
|
118
|
+
python setup.py develop --user
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then run the test:
|
|
122
|
+
|
|
123
|
+
```shell
|
|
124
|
+
pytest tests
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Run test with coverage
|
|
128
|
+
|
|
129
|
+
```shell
|
|
130
|
+
coverage run -m pytest
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Autobuild documentation
|
|
134
|
+
|
|
135
|
+
```shell
|
|
136
|
+
sphinx-autobuild docs docs/_build/html
|
|
137
|
+
```
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://pypi.org/project/sqlalchemyseed)
|
|
4
4
|
[](https://pypi.org/project/sqlalchemyseed)
|
|
5
5
|
[](https://github.com/jedymatt/sqlalchemyseed/blob/main/LICENSE)
|
|
6
|
-
[](https://github.com/jedymatt/sqlalchemyseed/actions/workflows/python-package.yml)
|
|
7
7
|
[](https://codeclimate.com/github/jedymatt/sqlalchemyseed/maintainability)
|
|
8
8
|
[](https://codecov.io/gh/jedymatt/sqlalchemyseed)
|
|
9
9
|
[](https://sqlalchemyseed.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -26,8 +26,9 @@ pip install sqlalchemyseed
|
|
|
26
26
|
|
|
27
27
|
## Quickstart
|
|
28
28
|
|
|
29
|
+
main.py
|
|
30
|
+
|
|
29
31
|
```python
|
|
30
|
-
# main.py
|
|
31
32
|
from sqlalchemyseed import load_entities_from_json
|
|
32
33
|
from sqlalchemyseed import Seeder
|
|
33
34
|
from db import session
|
|
@@ -45,6 +46,69 @@ seeder.seed(entities)
|
|
|
45
46
|
session.commit() # or seeder.session.commit()
|
|
46
47
|
```
|
|
47
48
|
|
|
49
|
+
data.json
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"model": "models.Person",
|
|
54
|
+
"data": [
|
|
55
|
+
{
|
|
56
|
+
"name": "John March",
|
|
57
|
+
"age": 23
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "Juan Dela Cruz",
|
|
61
|
+
"age": 21
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
48
67
|
## Documentation
|
|
49
68
|
|
|
50
69
|
<https://sqlalchemyseed.readthedocs.io/>
|
|
70
|
+
|
|
71
|
+
## Found Bug?
|
|
72
|
+
|
|
73
|
+
Report here in this link:
|
|
74
|
+
<https://github.com/jedymatt/sqlalchemyseed/issues>
|
|
75
|
+
|
|
76
|
+
## Want to contribute?
|
|
77
|
+
|
|
78
|
+
First, Clone this [repository](https://github.com/jedymatt/sqlalchemyseed).
|
|
79
|
+
|
|
80
|
+
### Install dev dependencies
|
|
81
|
+
|
|
82
|
+
Inside the folder, paste this in the terminal to install necessary dependencies:
|
|
83
|
+
|
|
84
|
+
```shell
|
|
85
|
+
pip install -r requirements.txt -r docs/requirements.txt
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Note: make sure you have the virtual environment and enabled, or if you are using vs code and docker then you can simply re-open this as container.
|
|
89
|
+
|
|
90
|
+
### Run tests
|
|
91
|
+
|
|
92
|
+
Before running tests, make sure that the package is installed as editable:
|
|
93
|
+
|
|
94
|
+
```shell
|
|
95
|
+
python setup.py develop --user
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Then run the test:
|
|
99
|
+
|
|
100
|
+
```shell
|
|
101
|
+
pytest tests
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Run test with coverage
|
|
105
|
+
|
|
106
|
+
```shell
|
|
107
|
+
coverage run -m pytest
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Autobuild documentation
|
|
111
|
+
|
|
112
|
+
```shell
|
|
113
|
+
sphinx-autobuild docs docs/_build/html
|
|
114
|
+
```
|
|
@@ -8,7 +8,8 @@ url = https://github.com/jedymatt/sqlalchemyseed
|
|
|
8
8
|
author = Jedy Matt Tabasco
|
|
9
9
|
author_email = jedymatt@gmail.com
|
|
10
10
|
license = MIT
|
|
11
|
-
|
|
11
|
+
license_files =
|
|
12
|
+
LICENSE
|
|
12
13
|
classifiers =
|
|
13
14
|
License :: OSI Approved :: MIT License
|
|
14
15
|
Programming Language :: Python :: 3.6
|
|
@@ -27,7 +28,7 @@ packages = find:
|
|
|
27
28
|
package_dir =
|
|
28
29
|
=src
|
|
29
30
|
install_requires =
|
|
30
|
-
SQLAlchemy>=1.4
|
|
31
|
+
SQLAlchemy>=1.4,<2.0
|
|
31
32
|
python_requires = >=3.6
|
|
32
33
|
|
|
33
34
|
[options.packages.find]
|
|
@@ -36,9 +37,6 @@ where = src
|
|
|
36
37
|
[options.extras_require]
|
|
37
38
|
yaml =
|
|
38
39
|
PyYAML>=5.4
|
|
39
|
-
docs =
|
|
40
|
-
sphinx-rtd-theme>=1.0
|
|
41
|
-
sphinx>=4.2
|
|
42
40
|
|
|
43
41
|
[egg_info]
|
|
44
42
|
tag_build =
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from setuptools import setup
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
setup()
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
setup()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SQLAlchemy seeder that supports nested relationships with an easy to read text files.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .seeder import HybridSeeder
|
|
6
|
+
from .seeder import Seeder
|
|
7
|
+
from .loader import load_entities_from_json
|
|
8
|
+
from .loader import load_entities_from_yaml
|
|
9
|
+
from .loader import load_entities_from_csv
|
|
10
|
+
from . import util
|
|
11
|
+
from . import attribute
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__version__ = "1.0.7"
|
|
15
|
+
|
|
16
|
+
if __name__ == '__main__':
|
|
17
|
+
pass
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
attribute module containing helper functions for instrumented attribute.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from functools import lru_cache
|
|
6
|
+
from inspect import isclass
|
|
7
|
+
|
|
8
|
+
from sqlalchemy.orm import ColumnProperty, RelationshipProperty
|
|
9
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute, get_attribute, set_attribute
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def instrumented_attribute(class_or_instance, key: str):
|
|
13
|
+
"""
|
|
14
|
+
Returns instrumented attribute from the class or instance.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
if isclass(class_or_instance):
|
|
18
|
+
return getattr(class_or_instance, key)
|
|
19
|
+
|
|
20
|
+
return getattr(class_or_instance.__class__, key)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def attr_is_relationship(instrumented_attr: InstrumentedAttribute):
|
|
24
|
+
"""
|
|
25
|
+
Check if instrumented attribute property is a RelationshipProperty
|
|
26
|
+
"""
|
|
27
|
+
return isinstance(instrumented_attr.property, RelationshipProperty)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def attr_is_column(instrumented_attr: InstrumentedAttribute):
|
|
31
|
+
"""
|
|
32
|
+
Check if instrumented attribute property is a ColumnProperty
|
|
33
|
+
"""
|
|
34
|
+
return isinstance(instrumented_attr.property, ColumnProperty)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def set_instance_attribute(instance, key, value):
|
|
38
|
+
"""
|
|
39
|
+
Set attribute value of instance
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
instr_attr: InstrumentedAttribute = getattr(instance.__class__, key)
|
|
43
|
+
|
|
44
|
+
if attr_is_relationship(instr_attr) and instr_attr.property.uselist:
|
|
45
|
+
get_attribute(instance, key).append(value)
|
|
46
|
+
else:
|
|
47
|
+
set_attribute(instance, key, value)
|
|
48
|
+
|
|
49
|
+
@lru_cache()
|
|
50
|
+
def foreign_key_column(instrumented_attr: InstrumentedAttribute):
|
|
51
|
+
"""
|
|
52
|
+
Returns the table name of the first foreignkey.
|
|
53
|
+
"""
|
|
54
|
+
return next(iter(instrumented_attr.foreign_keys)).column
|
|
55
|
+
|
|
56
|
+
@lru_cache()
|
|
57
|
+
def referenced_class(instrumented_attr: InstrumentedAttribute):
|
|
58
|
+
"""
|
|
59
|
+
Returns class that the attribute is referenced to.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
if attr_is_relationship(instrumented_attr):
|
|
63
|
+
return instrumented_attr.mapper.class_
|
|
64
|
+
|
|
65
|
+
table_name = foreign_key_column(instrumented_attr).table.name
|
|
66
|
+
|
|
67
|
+
return next(filter(
|
|
68
|
+
lambda mapper: mapper.class_.__tablename__ == table_name,
|
|
69
|
+
instrumented_attr.parent.registry.mappers
|
|
70
|
+
)).class_
|
|
@@ -1,43 +1,38 @@
|
|
|
1
1
|
class ClassNotFoundError(Exception):
|
|
2
2
|
"""Raised when the class is not found"""
|
|
3
|
-
pass
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
class MissingKeyError(Exception):
|
|
7
6
|
"""Raised when a required key is missing"""
|
|
8
|
-
pass
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
class MaxLengthExceededError(Exception):
|
|
12
10
|
"""Raised when maximum length of data exceeded"""
|
|
13
|
-
pass
|
|
14
11
|
|
|
15
12
|
|
|
16
13
|
class InvalidTypeError(Exception):
|
|
17
14
|
"""Raised when a type of data is not accepted"""
|
|
18
|
-
pass
|
|
19
15
|
|
|
20
16
|
|
|
21
17
|
class EmptyDataError(Exception):
|
|
22
18
|
"""Raised when data is empty"""
|
|
23
|
-
pass
|
|
24
19
|
|
|
25
20
|
|
|
26
21
|
class InvalidKeyError(Exception):
|
|
27
22
|
"""Raised when an invalid key is invoked"""
|
|
28
|
-
pass
|
|
29
23
|
|
|
30
24
|
|
|
31
25
|
class ParseError(Exception):
|
|
32
26
|
"""Raised when parsing string fails"""
|
|
33
|
-
pass
|
|
34
27
|
|
|
35
28
|
|
|
36
29
|
class UnsupportedClassError(Exception):
|
|
37
30
|
"""Raised when an unsupported class is invoked"""
|
|
38
|
-
pass
|
|
39
31
|
|
|
40
32
|
|
|
41
33
|
class NotInModuleError(Exception):
|
|
42
34
|
"""Raised when a value is not found in module"""
|
|
43
|
-
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class InvalidModelPath(Exception):
|
|
38
|
+
"""Raised when an invalid model path is invoked"""
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from typing import Callable, List, Union
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class JsonWalker:
|
|
5
|
+
"""
|
|
6
|
+
JsonWalker class
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, json: Union[list, dict] = None) -> None:
|
|
10
|
+
self.path = []
|
|
11
|
+
self.root = json
|
|
12
|
+
self._current = json
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def json(self):
|
|
16
|
+
"""
|
|
17
|
+
Returns current json
|
|
18
|
+
"""
|
|
19
|
+
return self._current
|
|
20
|
+
|
|
21
|
+
def keys(self):
|
|
22
|
+
"""
|
|
23
|
+
Returns list of keys either str or int
|
|
24
|
+
"""
|
|
25
|
+
if self.json_is_dict:
|
|
26
|
+
return self._current.keys()
|
|
27
|
+
|
|
28
|
+
if self.json_is_list:
|
|
29
|
+
return list(map(lambda index: index, range(len(self._current))))
|
|
30
|
+
|
|
31
|
+
return []
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def current_key(self) -> Union[int, str]:
|
|
35
|
+
"""
|
|
36
|
+
Returns the key of the current json
|
|
37
|
+
"""
|
|
38
|
+
return self.path[-1]
|
|
39
|
+
|
|
40
|
+
def forward(self, keys: List[Union[int, str]]):
|
|
41
|
+
"""
|
|
42
|
+
Move and replace current json forward.
|
|
43
|
+
Returns current json.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
if len(keys) == 0:
|
|
47
|
+
return self._current
|
|
48
|
+
|
|
49
|
+
self._current = self.find_from_current(keys)
|
|
50
|
+
self.path.extend(keys)
|
|
51
|
+
return self._current
|
|
52
|
+
|
|
53
|
+
def backward(self):
|
|
54
|
+
"""
|
|
55
|
+
Revert current json to its parent.
|
|
56
|
+
Returns reverted current json
|
|
57
|
+
"""
|
|
58
|
+
if len(self.path) == 0:
|
|
59
|
+
raise ValueError('No parent found error')
|
|
60
|
+
|
|
61
|
+
self._current = self.find_from_root(self.path[:-1])
|
|
62
|
+
self.path.pop()
|
|
63
|
+
|
|
64
|
+
def find_from_current(self, keys: List[Union[int, str]]):
|
|
65
|
+
"""
|
|
66
|
+
Find item from current json that correlates list of keys
|
|
67
|
+
"""
|
|
68
|
+
return self._find(self._current, keys)
|
|
69
|
+
|
|
70
|
+
def _find(self, json: Union[list, dict], keys: List[Union[int, str]]):
|
|
71
|
+
"""
|
|
72
|
+
Recursive call of finding item
|
|
73
|
+
"""
|
|
74
|
+
return self._find(json[keys[0]], keys[1:]) if keys else json
|
|
75
|
+
|
|
76
|
+
def find_from_root(self, keys: List[Union[int, str]]):
|
|
77
|
+
"""
|
|
78
|
+
Find item from the root json that correlates list of keys
|
|
79
|
+
"""
|
|
80
|
+
return self._find(self.root, keys)
|
|
81
|
+
|
|
82
|
+
def reset(self, root=None):
|
|
83
|
+
"""
|
|
84
|
+
Resets to initial state.
|
|
85
|
+
If root argument is supplied, self.root will be replaced.
|
|
86
|
+
"""
|
|
87
|
+
if root is not None:
|
|
88
|
+
self.root = root
|
|
89
|
+
|
|
90
|
+
self._current = self.root
|
|
91
|
+
self.path.clear()
|
|
92
|
+
|
|
93
|
+
def exec_func_iter(self, func: Callable):
|
|
94
|
+
"""
|
|
95
|
+
Executes function when iterating
|
|
96
|
+
"""
|
|
97
|
+
current = self._current
|
|
98
|
+
if self.json_is_dict:
|
|
99
|
+
for key in current.keys():
|
|
100
|
+
self.forward([key])
|
|
101
|
+
func()
|
|
102
|
+
self.backward()
|
|
103
|
+
elif self.json_is_list:
|
|
104
|
+
for index in range(len(current)):
|
|
105
|
+
self.forward([index])
|
|
106
|
+
func()
|
|
107
|
+
self.backward()
|
|
108
|
+
else:
|
|
109
|
+
func()
|
|
110
|
+
|
|
111
|
+
def iter_as_list(self):
|
|
112
|
+
"""
|
|
113
|
+
Iterates current as list.
|
|
114
|
+
Yields index and value.
|
|
115
|
+
|
|
116
|
+
Raises TypeError if current json is not list
|
|
117
|
+
"""
|
|
118
|
+
if not self.json_is_list:
|
|
119
|
+
raise TypeError('json is not list')
|
|
120
|
+
|
|
121
|
+
current = self._current
|
|
122
|
+
for index, value in enumerate(current):
|
|
123
|
+
self.forward([index])
|
|
124
|
+
yield index, value
|
|
125
|
+
self.backward()
|
|
126
|
+
|
|
127
|
+
def iter_as_dict_items(self):
|
|
128
|
+
"""
|
|
129
|
+
Iterates current as dict.
|
|
130
|
+
Yields key and value.
|
|
131
|
+
|
|
132
|
+
Raises TypeError if current json is not dict
|
|
133
|
+
"""
|
|
134
|
+
if not self.json_is_dict:
|
|
135
|
+
raise TypeError('json is not dict')
|
|
136
|
+
|
|
137
|
+
current = self._current
|
|
138
|
+
for key, value in current.items():
|
|
139
|
+
self.forward([key])
|
|
140
|
+
yield key, value
|
|
141
|
+
self.backward()
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def json_is_dict(self):
|
|
145
|
+
"""
|
|
146
|
+
Returns true if current json is dict
|
|
147
|
+
"""
|
|
148
|
+
return isinstance(self._current, dict)
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def json_is_list(self):
|
|
152
|
+
"""
|
|
153
|
+
Returns true if current json is list
|
|
154
|
+
"""
|
|
155
|
+
return isinstance(self._current, list)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def sort_json(json: Union[list, dict], reverse=False):
|
|
159
|
+
"""
|
|
160
|
+
Sort json function
|
|
161
|
+
"""
|
|
162
|
+
if isinstance(json, list):
|
|
163
|
+
return sorted(sorted(sort_json(item), reverse=reverse) for item in json)
|
|
164
|
+
|
|
165
|
+
if isinstance(json, dict):
|
|
166
|
+
return {key: sort_json(value, reverse=reverse) for key, value in json.items()}
|
|
167
|
+
|
|
168
|
+
return json
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Text file loader module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import csv
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import yaml
|
|
11
|
+
except ModuleNotFoundError: # pragma: no cover
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def load_entities_from_json(json_filepath) -> dict:
|
|
16
|
+
"""
|
|
17
|
+
Get entities from json
|
|
18
|
+
"""
|
|
19
|
+
try:
|
|
20
|
+
with open(json_filepath, 'r', encoding='utf-8') as file:
|
|
21
|
+
entities = json.loads(file.read())
|
|
22
|
+
except FileNotFoundError as error:
|
|
23
|
+
raise FileNotFoundError from error
|
|
24
|
+
|
|
25
|
+
return entities
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def load_entities_from_yaml(yaml_filepath):
|
|
29
|
+
"""
|
|
30
|
+
Get entities from yaml
|
|
31
|
+
"""
|
|
32
|
+
if 'yaml' not in sys.modules:
|
|
33
|
+
raise ModuleNotFoundError(
|
|
34
|
+
'PyYAML is not installed and is required to run this function. '
|
|
35
|
+
'To use this function, py -m pip install "sqlalchemyseed[yaml]"'
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
with open(yaml_filepath, 'r', encoding='utf-8') as file:
|
|
40
|
+
entities = yaml.load(file.read(), Loader=yaml.SafeLoader)
|
|
41
|
+
except FileNotFoundError as error:
|
|
42
|
+
raise FileNotFoundError from error
|
|
43
|
+
|
|
44
|
+
return entities
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def load_entities_from_csv(csv_filepath: str, model) -> dict:
|
|
48
|
+
"""Load entities from csv file
|
|
49
|
+
|
|
50
|
+
:param csv_filepath: string csv file path
|
|
51
|
+
:param model: either str or class
|
|
52
|
+
:return: dict of entities
|
|
53
|
+
"""
|
|
54
|
+
with open(csv_filepath, 'r', encoding='utf-8') as file:
|
|
55
|
+
source_data = list(
|
|
56
|
+
map(dict, csv.DictReader(file, skipinitialspace=True)))
|
|
57
|
+
if isinstance(model, str):
|
|
58
|
+
model_name = model
|
|
59
|
+
else:
|
|
60
|
+
model_name = '.'.join([model.__module__, model.__name__])
|
|
61
|
+
|
|
62
|
+
entities = {'model': model_name, 'data': source_data}
|
|
63
|
+
|
|
64
|
+
return entities
|