ramifice 0.3.27__py3-none-any.whl → 0.3.29__py3-none-any.whl
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.
- ramifice/__init__.py +2 -1
- ramifice/commons/__init__.py +1 -3
- ramifice/commons/general.py +9 -9
- ramifice/commons/indexes.py +7 -7
- ramifice/commons/many.py +19 -15
- ramifice/commons/one.py +23 -13
- ramifice/commons/tools.py +62 -57
- ramifice/commons/{units.py → unit_manager.py} +5 -7
- ramifice/fields/bool_field.py +3 -3
- ramifice/fields/choice_float_dyn_field.py +3 -3
- ramifice/fields/choice_float_field.py +3 -3
- ramifice/fields/choice_float_mult_dyn_field.py +3 -3
- ramifice/fields/choice_float_mult_field.py +3 -3
- ramifice/fields/choice_int_dyn_field.py +3 -3
- ramifice/fields/choice_int_field.py +3 -3
- ramifice/fields/choice_int_mult_dyn_field.py +3 -3
- ramifice/fields/choice_int_mult_field.py +3 -3
- ramifice/fields/choice_text_dyn_field.py +3 -3
- ramifice/fields/choice_text_field.py +3 -3
- ramifice/fields/choice_text_mult_dyn_field.py +3 -3
- ramifice/fields/choice_text_mult_field.py +3 -3
- ramifice/fields/color_field.py +4 -4
- ramifice/fields/date_field.py +2 -2
- ramifice/fields/date_time_field.py +2 -2
- ramifice/fields/email_field.py +3 -3
- ramifice/fields/file_field.py +4 -4
- ramifice/fields/float_field.py +3 -3
- ramifice/fields/id_field.py +2 -2
- ramifice/fields/image_field.py +4 -4
- ramifice/fields/integer_field.py +3 -3
- ramifice/fields/ip_field.py +3 -3
- ramifice/fields/password_field.py +2 -2
- ramifice/fields/phone_field.py +3 -3
- ramifice/fields/slug_field.py +3 -3
- ramifice/fields/text_field.py +3 -3
- ramifice/fields/url_field.py +3 -3
- ramifice/models/__init__.py +1 -0
- ramifice/{decorators.py → models/decorator.py} +11 -13
- ramifice/{model.py → models/model.py} +4 -4
- ramifice/{pseudo_model.py → models/pseudo.py} +4 -4
- ramifice/paladins/check.py +11 -11
- ramifice/paladins/delete.py +10 -10
- ramifice/paladins/groups/choice_group.py +1 -1
- ramifice/paladins/groups/date_group.py +1 -1
- ramifice/paladins/groups/file_group.py +2 -2
- ramifice/paladins/groups/id_group.py +1 -1
- ramifice/paladins/groups/img_group.py +2 -2
- ramifice/paladins/groups/num_group.py +1 -1
- ramifice/paladins/groups/pass_group.py +2 -2
- ramifice/paladins/groups/slug_group.py +1 -1
- ramifice/paladins/groups/text_group.py +3 -3
- ramifice/paladins/password.py +10 -10
- ramifice/paladins/refrash.py +7 -7
- ramifice/paladins/save.py +16 -16
- ramifice/paladins/tools.py +1 -1
- ramifice/paladins/validation.py +4 -4
- ramifice/utils/__init__.py +1 -0
- ramifice/{store.py → utils/globals.py} +2 -4
- ramifice/{migration.py → utils/migration.py} +17 -17
- ramifice/utils/mixins/__init__.py +6 -0
- ramifice/{add_valid.py → utils/mixins/add_valid.py} +2 -2
- ramifice/{hooks.py → utils/mixins/hooks.py} +2 -2
- ramifice/utils/mixins/indexing.py +11 -0
- ramifice/{mixins.py → utils/mixins/json_converter.py} +2 -5
- ramifice/{tools.py → utils/tools.py} +1 -1
- ramifice/{types.py → utils/unit.py} +2 -9
- {ramifice-0.3.27.dist-info → ramifice-0.3.29.dist-info}/METADATA +5 -6
- ramifice-0.3.29.dist-info/RECORD +85 -0
- ramifice/indexing.py +0 -11
- ramifice-0.3.27.dist-info/RECORD +0 -82
- /ramifice/{errors.py → utils/errors.py} +0 -0
- /ramifice/{fixtures.py → utils/fixtures.py} +0 -0
- /ramifice/{translations.py → utils/translations.py} +0 -0
- {ramifice-0.3.27.dist-info → ramifice-0.3.29.dist-info}/WHEEL +0 -0
- {ramifice-0.3.27.dist-info → ramifice-0.3.29.dist-info}/licenses/LICENSE +0 -0
ramifice/paladins/delete.py
CHANGED
|
@@ -6,8 +6,8 @@ from typing import Any
|
|
|
6
6
|
|
|
7
7
|
from pymongo.asynchronous.collection import AsyncCollection
|
|
8
8
|
|
|
9
|
-
from .. import
|
|
10
|
-
from ..errors import PanicError
|
|
9
|
+
from ..utils import globals
|
|
10
|
+
from ..utils.errors import PanicError
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class DeleteMixin:
|
|
@@ -27,26 +27,26 @@ class DeleteMixin:
|
|
|
27
27
|
"""Delete document from database."""
|
|
28
28
|
cls_model = self.__class__
|
|
29
29
|
# Raises a panic if the Model cannot be removed.
|
|
30
|
-
if not cls_model.META["is_delete_doc"]:
|
|
30
|
+
if not cls_model.META["is_delete_doc"]:
|
|
31
31
|
msg = (
|
|
32
|
-
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
32
|
+
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
33
33
|
+ "META param: `is_delete_doc` (False) => "
|
|
34
34
|
+ "Documents of this Model cannot be removed from the database!"
|
|
35
35
|
)
|
|
36
36
|
raise PanicError(msg)
|
|
37
37
|
# Get documet ID.
|
|
38
|
-
doc_id = self._id.value
|
|
38
|
+
doc_id = self._id.value
|
|
39
39
|
if doc_id is None:
|
|
40
40
|
msg = (
|
|
41
|
-
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
41
|
+
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
42
42
|
+ "Field: `_id` > "
|
|
43
43
|
+ "Param: `value` => ID is missing."
|
|
44
44
|
)
|
|
45
45
|
raise PanicError(msg)
|
|
46
46
|
# Run hook.
|
|
47
|
-
await self.pre_delete()
|
|
47
|
+
await self.pre_delete()
|
|
48
48
|
# Get collection for current Model.
|
|
49
|
-
collection: AsyncCollection =
|
|
49
|
+
collection: AsyncCollection = globals.MONGO_DATABASE[cls_model.META["collection_name"]]
|
|
50
50
|
# Delete document.
|
|
51
51
|
mongo_doc: dict[str, Any] = {}
|
|
52
52
|
mongo_doc = await collection.find_one_and_delete(
|
|
@@ -62,7 +62,7 @@ class DeleteMixin:
|
|
|
62
62
|
# If the document failed to delete.
|
|
63
63
|
if not bool(mongo_doc):
|
|
64
64
|
msg = (
|
|
65
|
-
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
65
|
+
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
66
66
|
+ "Method: `delete` => "
|
|
67
67
|
+ "The document was not deleted, the document is absent in the database."
|
|
68
68
|
)
|
|
@@ -86,6 +86,6 @@ class DeleteMixin:
|
|
|
86
86
|
file_data = None
|
|
87
87
|
field_data.value = None
|
|
88
88
|
# Run hook.
|
|
89
|
-
await self.post_delete()
|
|
89
|
+
await self.post_delete()
|
|
90
90
|
#
|
|
91
91
|
return mongo_doc
|
|
@@ -5,8 +5,8 @@ Supported fields: FileField
|
|
|
5
5
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
from ... import translations
|
|
9
|
-
from ...tools import to_human_size
|
|
8
|
+
from ...utils import translations
|
|
9
|
+
from ...utils.tools import to_human_size
|
|
10
10
|
from ..tools import accumulate_error, panic_type_error
|
|
11
11
|
|
|
12
12
|
|
|
@@ -7,8 +7,8 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from PIL import Image
|
|
9
9
|
|
|
10
|
-
from ... import translations
|
|
11
|
-
from ...tools import to_human_size
|
|
10
|
+
from ...utils import translations
|
|
11
|
+
from ...utils.tools import to_human_size
|
|
12
12
|
from ..tools import accumulate_error, panic_type_error
|
|
13
13
|
|
|
14
14
|
|
|
@@ -7,8 +7,8 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from argon2 import PasswordHasher
|
|
9
9
|
|
|
10
|
-
from ... import translations
|
|
11
|
-
from ...tools import is_password
|
|
10
|
+
from ...utils import translations
|
|
11
|
+
from ...utils.tools import is_password
|
|
12
12
|
from ..tools import accumulate_error, panic_type_error
|
|
13
13
|
|
|
14
14
|
|
|
@@ -9,8 +9,8 @@ from typing import Any
|
|
|
9
9
|
|
|
10
10
|
from email_validator import EmailNotValidError, validate_email
|
|
11
11
|
|
|
12
|
-
from ... import translations
|
|
13
|
-
from ...tools import is_color, is_ip, is_phone, is_url
|
|
12
|
+
from ...utils import translations
|
|
13
|
+
from ...utils.tools import is_color, is_ip, is_phone, is_url
|
|
14
14
|
from ..tools import accumulate_error, check_uniqueness, panic_type_error
|
|
15
15
|
|
|
16
16
|
|
|
@@ -53,7 +53,7 @@ class TextGroupMixin:
|
|
|
53
53
|
try:
|
|
54
54
|
emailinfo = validate_email(
|
|
55
55
|
str(value),
|
|
56
|
-
check_deliverability=self.__class__.META["is_migrate_model"],
|
|
56
|
+
check_deliverability=self.__class__.META["is_migrate_model"],
|
|
57
57
|
)
|
|
58
58
|
value = emailinfo.normalized
|
|
59
59
|
params["field_data"].value = value
|
ramifice/paladins/password.py
CHANGED
|
@@ -5,8 +5,8 @@ from typing import Any
|
|
|
5
5
|
from argon2 import PasswordHasher
|
|
6
6
|
from pymongo.asynchronous.collection import AsyncCollection
|
|
7
7
|
|
|
8
|
-
from .. import
|
|
9
|
-
from ..errors import OldPassNotMatchError, PanicError
|
|
8
|
+
from ..utils import globals
|
|
9
|
+
from ..utils.errors import OldPassNotMatchError, PanicError
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class PasswordMixin:
|
|
@@ -20,30 +20,30 @@ class PasswordMixin:
|
|
|
20
20
|
"""For password verification."""
|
|
21
21
|
cls_model = self.__class__
|
|
22
22
|
# Get documet ID.
|
|
23
|
-
doc_id = self._id.value
|
|
23
|
+
doc_id = self._id.value
|
|
24
24
|
if doc_id is None:
|
|
25
25
|
msg = (
|
|
26
|
-
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
26
|
+
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
27
27
|
+ "Method: `verify_password` => "
|
|
28
28
|
+ "Cannot get document ID - ID field is empty."
|
|
29
29
|
)
|
|
30
30
|
raise PanicError(msg)
|
|
31
31
|
# Get collection for current Model.
|
|
32
|
-
collection: AsyncCollection =
|
|
32
|
+
collection: AsyncCollection = globals.MONGO_DATABASE[cls_model.META["collection_name"]]
|
|
33
33
|
# Get document.
|
|
34
34
|
mongo_doc: dict[str, Any] | None = await collection.find_one({"_id": doc_id})
|
|
35
35
|
if mongo_doc is None:
|
|
36
36
|
msg = (
|
|
37
|
-
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
37
|
+
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
38
38
|
+ "Method: `verify_password` => "
|
|
39
|
-
+ f"There is no document with ID `{self._id.value}` in the database."
|
|
39
|
+
+ f"There is no document with ID `{self._id.value}` in the database."
|
|
40
40
|
)
|
|
41
41
|
raise PanicError(msg)
|
|
42
42
|
# Get password hash.
|
|
43
43
|
hash: str | None = mongo_doc.get(field_name)
|
|
44
44
|
if hash is None:
|
|
45
45
|
msg = (
|
|
46
|
-
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
46
|
+
f"Model: `{cls_model.META['full_model_name']}` > "
|
|
47
47
|
+ "Method: `verify_password` => "
|
|
48
48
|
+ f"The model does not have a field `{field_name}`."
|
|
49
49
|
)
|
|
@@ -73,9 +73,9 @@ class PasswordMixin:
|
|
|
73
73
|
if not await self.verify_password(old_password, field_name):
|
|
74
74
|
raise OldPassNotMatchError()
|
|
75
75
|
# Get documet ID.
|
|
76
|
-
doc_id = self._id.value
|
|
76
|
+
doc_id = self._id.value
|
|
77
77
|
# Get collection for current Model.
|
|
78
|
-
collection: AsyncCollection =
|
|
78
|
+
collection: AsyncCollection = globals.MONGO_DATABASE[cls_model.META["collection_name"]]
|
|
79
79
|
# Create hash of new passwor.
|
|
80
80
|
ph = PasswordHasher()
|
|
81
81
|
hash: str = ph.hash(new_password)
|
ramifice/paladins/refrash.py
CHANGED
|
@@ -4,8 +4,8 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
from pymongo.asynchronous.collection import AsyncCollection
|
|
6
6
|
|
|
7
|
-
from .. import
|
|
8
|
-
from ..errors import PanicError
|
|
7
|
+
from ..utils import globals
|
|
8
|
+
from ..utils.errors import PanicError
|
|
9
9
|
from .tools import refresh_from_mongo_doc
|
|
10
10
|
|
|
11
11
|
|
|
@@ -16,14 +16,14 @@ class RefrashMixin:
|
|
|
16
16
|
"""Update Model instance from database."""
|
|
17
17
|
cls_model = self.__class__
|
|
18
18
|
# Get collection.
|
|
19
|
-
collection: AsyncCollection =
|
|
20
|
-
mongo_doc: dict[str, Any] | None = await collection.find_one(filter={"_id": self._id.value})
|
|
19
|
+
collection: AsyncCollection = globals.MONGO_DATABASE[cls_model.META["collection_name"]]
|
|
20
|
+
mongo_doc: dict[str, Any] | None = await collection.find_one(filter={"_id": self._id.value})
|
|
21
21
|
if mongo_doc is None:
|
|
22
22
|
msg = (
|
|
23
|
-
f"Model: `{self.full_model_name()}` > "
|
|
23
|
+
f"Model: `{self.full_model_name()}` > "
|
|
24
24
|
+ "Method: `refrash_from_db` => "
|
|
25
|
-
+ f"A document with an identifier `{self._id.value}` is not exists in the database!"
|
|
25
|
+
+ f"A document with an identifier `{self._id.value}` is not exists in the database!"
|
|
26
26
|
)
|
|
27
27
|
raise PanicError(msg)
|
|
28
|
-
self.inject()
|
|
28
|
+
self.inject()
|
|
29
29
|
refresh_from_mongo_doc(self, mongo_doc)
|
ramifice/paladins/save.py
CHANGED
|
@@ -5,8 +5,8 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
from pymongo.asynchronous.collection import AsyncCollection
|
|
7
7
|
|
|
8
|
-
from .. import
|
|
9
|
-
from ..errors import PanicError
|
|
8
|
+
from ..utils import globals
|
|
9
|
+
from ..utils.errors import PanicError
|
|
10
10
|
from .tools import ignored_fields_to_none, refresh_from_mongo_doc
|
|
11
11
|
|
|
12
12
|
|
|
@@ -20,17 +20,17 @@ class SaveMixin:
|
|
|
20
20
|
"""
|
|
21
21
|
cls_model = self.__class__
|
|
22
22
|
# Get collection.
|
|
23
|
-
collection: AsyncCollection =
|
|
23
|
+
collection: AsyncCollection = globals.MONGO_DATABASE[cls_model.META["collection_name"]]
|
|
24
24
|
# Check Model.
|
|
25
|
-
result_check: dict[str, Any] = await self.check(is_save=True, collection=collection)
|
|
25
|
+
result_check: dict[str, Any] = await self.check(is_save=True, collection=collection)
|
|
26
26
|
# Reset the alerts to exclude duplicates.
|
|
27
|
-
self._id.alerts = []
|
|
27
|
+
self._id.alerts = []
|
|
28
28
|
# Check the conditions and, if necessary, define a message for the web form.
|
|
29
|
-
if not result_check["is_update"] and not cls_model.META["is_create_doc"]:
|
|
30
|
-
self._id.alerts.append("It is forbidden to create new documents !")
|
|
29
|
+
if not result_check["is_update"] and not cls_model.META["is_create_doc"]:
|
|
30
|
+
self._id.alerts.append("It is forbidden to create new documents !")
|
|
31
31
|
result_check["is_valid"] = False
|
|
32
|
-
if result_check["is_update"] and not cls_model.META["is_update_doc"]:
|
|
33
|
-
self._id.alerts.append("It is forbidden to update documents !")
|
|
32
|
+
if result_check["is_update"] and not cls_model.META["is_update_doc"]:
|
|
33
|
+
self._id.alerts.append("It is forbidden to update documents !")
|
|
34
34
|
result_check["is_valid"] = False
|
|
35
35
|
# Leave the method if the check fails.
|
|
36
36
|
if not result_check["is_valid"]:
|
|
@@ -43,18 +43,18 @@ class SaveMixin:
|
|
|
43
43
|
# Update date and time.
|
|
44
44
|
checked_data["updated_at"] = datetime.now()
|
|
45
45
|
# Run hook.
|
|
46
|
-
await self.pre_update()
|
|
46
|
+
await self.pre_update()
|
|
47
47
|
# Update doc.
|
|
48
48
|
await collection.update_one({"_id": checked_data["_id"]}, {"$set": checked_data})
|
|
49
49
|
# Run hook.
|
|
50
|
-
await self.post_update()
|
|
50
|
+
await self.post_update()
|
|
51
51
|
# Refresh Model.
|
|
52
52
|
mongo_doc: dict[str, Any] | None = await collection.find_one(
|
|
53
53
|
{"_id": checked_data["_id"]}
|
|
54
54
|
)
|
|
55
55
|
if mongo_doc is None:
|
|
56
56
|
msg = (
|
|
57
|
-
f"Model: `{self.full_model_name()}` > "
|
|
57
|
+
f"Model: `{self.full_model_name()}` > "
|
|
58
58
|
+ "Method: `save` => "
|
|
59
59
|
+ "Geted value is None - it is impossible to refresh the current Model."
|
|
60
60
|
)
|
|
@@ -66,16 +66,16 @@ class SaveMixin:
|
|
|
66
66
|
checked_data["created_at"] = today
|
|
67
67
|
checked_data["updated_at"] = today
|
|
68
68
|
# Run hook.
|
|
69
|
-
await self.pre_create()
|
|
69
|
+
await self.pre_create()
|
|
70
70
|
# Insert doc.
|
|
71
71
|
await collection.insert_one(checked_data)
|
|
72
72
|
# Run hook.
|
|
73
|
-
await self.post_create()
|
|
73
|
+
await self.post_create()
|
|
74
74
|
# Refresh Model.
|
|
75
75
|
mongo_doc = await collection.find_one({"_id": checked_data["_id"]})
|
|
76
76
|
if mongo_doc is None:
|
|
77
77
|
msg = (
|
|
78
|
-
f"Model: `{self.full_model_name()}` > "
|
|
78
|
+
f"Model: `{self.full_model_name()}` > "
|
|
79
79
|
+ "Method: `save` => "
|
|
80
80
|
+ "Geted value is None - it is impossible to refresh the current Model."
|
|
81
81
|
)
|
|
@@ -84,7 +84,7 @@ class SaveMixin:
|
|
|
84
84
|
refresh_from_mongo_doc(self, mongo_doc)
|
|
85
85
|
else:
|
|
86
86
|
msg = (
|
|
87
|
-
f"Model: `{self.full_model_name()}` > "
|
|
87
|
+
f"Model: `{self.full_model_name()}` > "
|
|
88
88
|
+ "Method: `save` => "
|
|
89
89
|
+ "The document was not created."
|
|
90
90
|
)
|
ramifice/paladins/tools.py
CHANGED
ramifice/paladins/validation.py
CHANGED
|
@@ -14,7 +14,7 @@ class ValidationMixin:
|
|
|
14
14
|
The main use is to check data from web forms.
|
|
15
15
|
It is also used to verify Models that do not migrate to the database.
|
|
16
16
|
"""
|
|
17
|
-
result_check: dict[str, Any] = await self.check()
|
|
17
|
+
result_check: dict[str, Any] = await self.check()
|
|
18
18
|
return result_check["is_valid"]
|
|
19
19
|
|
|
20
20
|
def print_err(self) -> None:
|
|
@@ -31,17 +31,17 @@ class ValidationMixin:
|
|
|
31
31
|
if not is_err:
|
|
32
32
|
print(colored("\nERRORS:", "red", attrs=["bold"]))
|
|
33
33
|
print(colored("Model: ", "blue", attrs=["bold"]), end="")
|
|
34
|
-
print(colored(f"`{self.full_model_name()}`", "blue"))
|
|
34
|
+
print(colored(f"`{self.full_model_name()}`", "blue"))
|
|
35
35
|
is_err = True
|
|
36
36
|
# field name
|
|
37
37
|
print(colored("Field: ", "green", attrs=["bold"]), end="")
|
|
38
38
|
print(colored(f"`{field_name}`:", "green"))
|
|
39
39
|
# error messages
|
|
40
40
|
print(colored("\n".join(field_data.errors), "red"))
|
|
41
|
-
if len(self._id.alerts) > 0:
|
|
41
|
+
if len(self._id.alerts) > 0:
|
|
42
42
|
# title
|
|
43
43
|
print(colored("AlERTS:", "yellow", attrs=["bold"]))
|
|
44
44
|
# messages
|
|
45
|
-
print(colored("\n".join(self._id.alerts), "yellow"), end="\n\n")
|
|
45
|
+
print(colored("\n".join(self._id.alerts), "yellow"), end="\n\n")
|
|
46
46
|
else:
|
|
47
47
|
print(end="\n\n")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""A set of Ramifice useful utilities."""
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
"""Global
|
|
1
|
+
"""Global variables.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
The module contains the following elements:
|
|
3
|
+
List of variables:
|
|
6
4
|
|
|
7
5
|
- `DEBUG` - Caching a condition for the verification code.
|
|
8
6
|
- `MONGO_CLIENT` - Caching a Mongo client.
|
|
@@ -11,25 +11,25 @@ from pymongo import AsyncMongoClient
|
|
|
11
11
|
from pymongo.asynchronous.collection import AsyncCollection
|
|
12
12
|
from termcolor import colored
|
|
13
13
|
|
|
14
|
-
from . import
|
|
14
|
+
from ..models.model import Model
|
|
15
|
+
from . import globals
|
|
15
16
|
from .errors import DoesNotMatchRegexError, NoModelsForMigrationError, PanicError
|
|
16
17
|
from .fixtures import apply_fixture
|
|
17
|
-
from .model import Model
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class Monitor:
|
|
21
21
|
"""Monitoring and updating database state for application."""
|
|
22
22
|
|
|
23
23
|
def __init__(self, database_name: str, mongo_client: AsyncMongoClient): # noqa: D107
|
|
24
|
-
|
|
24
|
+
globals.DEBUG = False
|
|
25
25
|
#
|
|
26
|
-
db_name_regex =
|
|
26
|
+
db_name_regex = globals.REGEX["database_name"]
|
|
27
27
|
if db_name_regex.match(database_name) is None:
|
|
28
28
|
raise DoesNotMatchRegexError("^[a-zA-Z][-_a-zA-Z0-9]{0,59}$")
|
|
29
29
|
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
globals.DATABASE_NAME = database_name
|
|
31
|
+
globals.MONGO_CLIENT = mongo_client
|
|
32
|
+
globals.MONGO_DATABASE = globals.MONGO_CLIENT[globals.DATABASE_NAME]
|
|
33
33
|
# Get Model list.
|
|
34
34
|
self.model_list: list[Any] = [
|
|
35
35
|
cls_model for cls_model in Model.__subclasses__() if cls_model.META["is_migrate_model"]
|
|
@@ -45,7 +45,7 @@ class Monitor:
|
|
|
45
45
|
"""
|
|
46
46
|
# Get access to super collection.
|
|
47
47
|
# (Contains Model state and dynamic field data.)
|
|
48
|
-
super_collection: AsyncCollection =
|
|
48
|
+
super_collection: AsyncCollection = globals.MONGO_DATABASE[globals.SUPER_COLLECTION_NAME]
|
|
49
49
|
# Switch the `is_model_exist` parameter in `False`.
|
|
50
50
|
async for model_state in super_collection.find():
|
|
51
51
|
q_filter = {"collection_name": model_state["collection_name"]}
|
|
@@ -56,7 +56,7 @@ class Monitor:
|
|
|
56
56
|
"""Get the state of the current model from a super collection."""
|
|
57
57
|
# Get access to super collection.
|
|
58
58
|
# (Contains Model state and dynamic field data.)
|
|
59
|
-
super_collection: AsyncCollection =
|
|
59
|
+
super_collection: AsyncCollection = globals.MONGO_DATABASE[globals.SUPER_COLLECTION_NAME]
|
|
60
60
|
# Get state of current Model.
|
|
61
61
|
model_state: dict[str, Any] | None = await super_collection.find_one(
|
|
62
62
|
{"collection_name": metadata["collection_name"]}
|
|
@@ -88,10 +88,10 @@ class Monitor:
|
|
|
88
88
|
delete collections associated with those Models.
|
|
89
89
|
""" # noqa: D205
|
|
90
90
|
# Get access to database.
|
|
91
|
-
database =
|
|
91
|
+
database = globals.MONGO_DATABASE
|
|
92
92
|
# Get access to super collection.
|
|
93
93
|
# (Contains Model state and dynamic field data.)
|
|
94
|
-
super_collection: AsyncCollection =
|
|
94
|
+
super_collection: AsyncCollection = globals.MONGO_DATABASE[globals.SUPER_COLLECTION_NAME]
|
|
95
95
|
# Delete data for non-existent Models.
|
|
96
96
|
async for model_state in super_collection.find():
|
|
97
97
|
if model_state["is_model_exist"] is False:
|
|
@@ -113,9 +113,9 @@ class Monitor:
|
|
|
113
113
|
# Switch the `is_model_exist` parameter in the condition `False`.
|
|
114
114
|
await self.reset()
|
|
115
115
|
# Get access to database.
|
|
116
|
-
database =
|
|
116
|
+
database = globals.MONGO_DATABASE
|
|
117
117
|
# Get access to super collection.
|
|
118
|
-
super_collection: AsyncCollection = database[
|
|
118
|
+
super_collection: AsyncCollection = database[globals.SUPER_COLLECTION_NAME]
|
|
119
119
|
#
|
|
120
120
|
for cls_model in self.model_list:
|
|
121
121
|
# Get metadata of current Model.
|
|
@@ -128,7 +128,7 @@ class Monitor:
|
|
|
128
128
|
# Get a list of new fields.
|
|
129
129
|
new_fields: list[str] = self.new_fields(metadata, model_state)
|
|
130
130
|
# Get collection for current Model.
|
|
131
|
-
model_collection: AsyncCollection = database[model_state["collection_name"]]
|
|
131
|
+
model_collection: AsyncCollection = database[model_state["collection_name"]]
|
|
132
132
|
# Add new fields with default value or
|
|
133
133
|
# update existing fields whose field type has changed.
|
|
134
134
|
async for mongo_doc in model_collection.find():
|
|
@@ -194,7 +194,7 @@ class Monitor:
|
|
|
194
194
|
)
|
|
195
195
|
#
|
|
196
196
|
# Block the verification code.
|
|
197
|
-
|
|
197
|
+
globals.DEBUG = False
|
|
198
198
|
#
|
|
199
199
|
# Delete data for non-existent Models from a
|
|
200
200
|
# super collection and delete collections associated with those Models.
|
|
@@ -206,8 +206,8 @@ class Monitor:
|
|
|
206
206
|
# Apply fixture to current Model.
|
|
207
207
|
fixture_name: str | None = cls_model.META["fixture_name"]
|
|
208
208
|
if fixture_name is not None:
|
|
209
|
-
collection: AsyncCollection =
|
|
210
|
-
cls_model.META["collection_name"]
|
|
209
|
+
collection: AsyncCollection = globals.MONGO_DATABASE[
|
|
210
|
+
cls_model.META["collection_name"]
|
|
211
211
|
]
|
|
212
212
|
if await collection.estimated_document_count() == 0:
|
|
213
213
|
await apply_fixture(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""AddValidMixin - Contains an abstract method for additional validation of fields."""
|
|
2
2
|
|
|
3
3
|
from abc import ABCMeta
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class AddValidMixin(metaclass=ABCMeta):
|
|
7
|
-
"""
|
|
7
|
+
"""Contains an abstract method for additional validation of fields."""
|
|
8
8
|
|
|
9
9
|
async def add_validation(self) -> dict[str, str]:
|
|
10
10
|
"""Additional validation of fields."""
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""HooksMixin - Contains abstract methods for creating hooks."""
|
|
2
2
|
|
|
3
3
|
from abc import ABCMeta
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class HooksMixin(metaclass=ABCMeta):
|
|
7
|
-
"""
|
|
7
|
+
"""A set of abstract methods for creating hooks."""
|
|
8
8
|
|
|
9
9
|
async def pre_create(self) -> None:
|
|
10
10
|
"""Called before a new document is created in the database."""
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""IndexMixin - Contains abstract method for indexing the model in the database."""
|
|
2
|
+
|
|
3
|
+
from abc import ABCMeta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IndexMixin(metaclass=ABCMeta):
|
|
7
|
+
"""Contains the method for indexing the model in the database."""
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
async def indexing(cls) -> None:
|
|
11
|
+
"""For set up and start indexing."""
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""JsonMixin - Contains the methods for converting Fields to JSON and back."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class JsonMixin:
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
For fields FileField and ImageField is used FileJsonMixin.
|
|
11
|
-
"""
|
|
8
|
+
"""Contains the methods for converting Fields to JSON and back."""
|
|
12
9
|
|
|
13
10
|
def to_dict(self) -> dict[str, Any]:
|
|
14
11
|
"""Convert object instance to a dictionary."""
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
These types are used to transfer information.
|
|
4
|
-
|
|
5
|
-
The module contains the following types:
|
|
6
|
-
|
|
7
|
-
- `Unit` - Used for data management in dynamic fields.
|
|
8
|
-
"""
|
|
1
|
+
"""Unit - Data management in dynamic fields."""
|
|
9
2
|
|
|
10
3
|
from .errors import PanicError
|
|
11
|
-
from .mixins import JsonMixin
|
|
4
|
+
from .mixins.json_converter import JsonMixin
|
|
12
5
|
|
|
13
6
|
|
|
14
7
|
class Unit(JsonMixin):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ramifice
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.29
|
|
4
4
|
Summary: ORM-like API MongoDB for Python language.
|
|
5
5
|
Project-URL: Homepage, https://github.com/kebasyaty/ramifice
|
|
6
6
|
Project-URL: Documentation, https://kebasyaty.github.io/ramifice/
|
|
@@ -134,9 +134,8 @@ import pprint
|
|
|
134
134
|
from datetime import datetime
|
|
135
135
|
|
|
136
136
|
from pymongo import AsyncMongoClient
|
|
137
|
-
from ramifice import model, translations
|
|
137
|
+
from ramifice import model, translations, migration
|
|
138
138
|
from ramifice.fields import DateField, EmailField, ImageField, PasswordField, TextField
|
|
139
|
-
from ramifice.migration import Monitor
|
|
140
139
|
|
|
141
140
|
|
|
142
141
|
@model(service_name="Accounts")
|
|
@@ -192,7 +191,7 @@ class User:
|
|
|
192
191
|
async def main():
|
|
193
192
|
client = AsyncMongoClient()
|
|
194
193
|
|
|
195
|
-
await Monitor(
|
|
194
|
+
await migration.Monitor(
|
|
196
195
|
database_name="test_db",
|
|
197
196
|
mongo_client=client,
|
|
198
197
|
).migrat()
|
|
@@ -474,7 +473,7 @@ async for index in await User.list_indexes():
|
|
|
474
473
|
# Units Management.
|
|
475
474
|
# Management for `choices` parameter in dynamic field types.
|
|
476
475
|
# Units are stored in a separate collection.
|
|
477
|
-
from ramifice.
|
|
476
|
+
from ramifice.utils.unit import Unit
|
|
478
477
|
unit = Unit(
|
|
479
478
|
field="field_name", # The name of the dynamic field.
|
|
480
479
|
title="Title", # The name of the choice item.
|
|
@@ -522,7 +521,7 @@ await user.update_password( # + verify_password
|
|
|
522
521
|
## General auxiliary methods
|
|
523
522
|
|
|
524
523
|
```python
|
|
525
|
-
from ramifice.tools import (
|
|
524
|
+
from ramifice.utils.tools import (
|
|
526
525
|
get_file_size,
|
|
527
526
|
hash_to_obj_id,
|
|
528
527
|
is_color,
|