scruby 0.9.3__py3-none-any.whl → 0.17.0__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.
- scruby/__init__.py +29 -29
- scruby/aggregation.py +148 -0
- scruby/constants.py +31 -31
- scruby/db.py +756 -301
- scruby/errors.py +39 -0
- {scruby-0.9.3.dist-info → scruby-0.17.0.dist-info}/METADATA +41 -33
- scruby-0.17.0.dist-info/RECORD +10 -0
- {scruby-0.9.3.dist-info → scruby-0.17.0.dist-info}/licenses/LICENSE +21 -21
- scruby-0.9.3.dist-info/RECORD +0 -8
- {scruby-0.9.3.dist-info → scruby-0.17.0.dist-info}/WHEEL +0 -0
scruby/errors.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Scruby Exceptions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"ScrubyException",
|
|
7
|
+
"MetadataValueError",
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ScrubyException(Exception):
|
|
12
|
+
"""Root Custom Exception."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def] # noqa: D107
|
|
15
|
+
super().__init__(*args, **kwargs)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MetadataValueError(ScrubyException):
|
|
19
|
+
"""Exception is raised if value of variable in metadata does not matching expected."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, message: str) -> None: # noqa: D107
|
|
22
|
+
self.message = message
|
|
23
|
+
super().__init__(self.message)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class KeyAlreadyExistsError(ScrubyException):
|
|
27
|
+
"""Exception is raised if the key already exists."""
|
|
28
|
+
|
|
29
|
+
def __init__(self) -> None:
|
|
30
|
+
self.message = "The key already exists."
|
|
31
|
+
super().__init__(self.message)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class KeyNotExistsError(ScrubyException):
|
|
35
|
+
"""Exception is raised If the key is not exists."""
|
|
36
|
+
|
|
37
|
+
def __init__(self) -> None:
|
|
38
|
+
self.message = "The key not exists."
|
|
39
|
+
super().__init__(self.message)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scruby
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.0
|
|
4
4
|
Summary: A fast key-value storage library.
|
|
5
5
|
Project-URL: Homepage, https://github.com/kebasyaty/scruby
|
|
6
6
|
Project-URL: Repository, https://github.com/kebasyaty/scruby
|
|
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
25
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
26
|
Classifier: Topic :: Database
|
|
26
27
|
Classifier: Typing :: Typed
|
|
@@ -43,7 +44,7 @@ Description-Content-Type: text/markdown
|
|
|
43
44
|
</p>
|
|
44
45
|
<p>
|
|
45
46
|
<h1>Scruby</h1>
|
|
46
|
-
<h3>
|
|
47
|
+
<h3>Asynchronous library for building and managing a hybrid database,<br>by scheme of key-value.</h3>
|
|
47
48
|
<p align="center">
|
|
48
49
|
<a href="https://github.com/kebasyaty/scruby/actions/workflows/test.yml" alt="Build Status"><img src="https://github.com/kebasyaty/scruby/actions/workflows/test.yml/badge.svg" alt="Build Status"></a>
|
|
49
50
|
<a href="https://kebasyaty.github.io/scruby/" alt="Docs"><img src="https://img.shields.io/badge/docs-available-brightgreen.svg" alt="Docs"></a>
|
|
@@ -51,34 +52,30 @@ Description-Content-Type: text/markdown
|
|
|
51
52
|
<a href="https://pypi.python.org/pypi/scruby/" alt="PyPI status"><img src="https://img.shields.io/pypi/status/scruby.svg" alt="PyPI status"></a>
|
|
52
53
|
<a href="https://pypi.python.org/pypi/scruby/" alt="PyPI version fury.io"><img src="https://badge.fury.io/py/scruby.svg" alt="PyPI version fury.io"></a>
|
|
53
54
|
<br>
|
|
54
|
-
<a href="https://github.com/kebasyaty/scruby/issues"><img src="https://img.shields.io/github/issues/kebasyaty/scruby.svg" alt="GitHub issues"></a>
|
|
55
|
-
<a href="https://pepy.tech/projects/scruby"><img src="https://static.pepy.tech/badge/scruby" alt="PyPI Downloads"></a>
|
|
56
|
-
<a href="https://github.com/kebasyaty/scruby/blob/main/LICENSE" alt="GitHub license"><img src="https://img.shields.io/github/license/kebasyaty/scruby" alt="GitHub license"></a>
|
|
57
55
|
<a href="https://mypy-lang.org/" alt="Types: Mypy"><img src="https://img.shields.io/badge/types-Mypy-202235.svg?color=0c7ebf" alt="Types: Mypy"></a>
|
|
58
56
|
<a href="https://docs.astral.sh/ruff/" alt="Code style: Ruff"><img src="https://img.shields.io/badge/code%20style-Ruff-FDD835.svg" alt="Code style: Ruff"></a>
|
|
59
|
-
<a href="https://github.com/kebasyaty/scruby" alt="PyPI implementation"><img src="https://img.shields.io/pypi/implementation/scruby" alt="PyPI implementation"></a>
|
|
60
|
-
<br>
|
|
61
57
|
<a href="https://pypi.org/project/scruby"><img src="https://img.shields.io/pypi/format/scruby" alt="Format"></a>
|
|
62
|
-
<a href="https://
|
|
63
|
-
<a href="https://github.com/kebasyaty/scruby"><img src="https://img.shields.io/github/
|
|
64
|
-
<a href="https://github.com/kebasyaty/scruby"><img src="https://img.shields.io/github/last-commit/kebasyaty/scruby/main" alt="Last commit"></a>
|
|
65
|
-
<a href="https://github.com/kebasyaty/scruby/releases/" alt="GitHub release"><img src="https://img.shields.io/github/release/kebasyaty/scruby" alt="GitHub release"></a>
|
|
58
|
+
<a href="https://pepy.tech/projects/scruby"><img src="https://static.pepy.tech/badge/scruby" alt="PyPI Downloads"></a>
|
|
59
|
+
<a href="https://github.com/kebasyaty/scruby/blob/main/LICENSE" alt="GitHub license"><img src="https://img.shields.io/github/license/kebasyaty/scruby" alt="GitHub license"></a>
|
|
66
60
|
</p>
|
|
67
61
|
<p align="center">
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
62
|
+
The library uses fractal-tree addressing and
|
|
63
|
+
<br>
|
|
64
|
+
the search for documents based on the effect of a quantum loop.
|
|
65
|
+
<br>
|
|
66
|
+
The database consists of collections.
|
|
67
|
+
<br>
|
|
68
|
+
The maximum size of the one collection is 16\*\*8=4294967296 branches,
|
|
69
|
+
<br>
|
|
70
|
+
each branch can store one or more keys.
|
|
71
|
+
<br>
|
|
72
|
+
The value of any key in collection can be obtained in 8 steps,
|
|
73
|
+
<br>
|
|
74
|
+
thereby achieving high performance.
|
|
75
|
+
<br>
|
|
76
|
+
The effectiveness of the search for documents based on a quantum loop,
|
|
77
|
+
<br>
|
|
78
|
+
requires a large number of processor threads.
|
|
82
79
|
</p>
|
|
83
80
|
</p>
|
|
84
81
|
</div>
|
|
@@ -117,6 +114,7 @@ from scruby import Scruby, constants
|
|
|
117
114
|
|
|
118
115
|
constants.DB_ROOT = "ScrubyDB" # By default = "ScrubyDB"
|
|
119
116
|
|
|
117
|
+
|
|
120
118
|
class User(BaseModel):
|
|
121
119
|
"""Model of User."""
|
|
122
120
|
first_name: str
|
|
@@ -125,6 +123,7 @@ class User(BaseModel):
|
|
|
125
123
|
email: EmailStr
|
|
126
124
|
phone: Annotated[PhoneNumber, PhoneNumberValidator(number_format="E164")]
|
|
127
125
|
|
|
126
|
+
|
|
128
127
|
async def main() -> None:
|
|
129
128
|
"""Example."""
|
|
130
129
|
# Get collection of `User`.
|
|
@@ -138,7 +137,9 @@ async def main() -> None:
|
|
|
138
137
|
phone="+447986123456",
|
|
139
138
|
)
|
|
140
139
|
|
|
141
|
-
await user_coll.
|
|
140
|
+
await user_coll.add_key(user.phone, user)
|
|
141
|
+
|
|
142
|
+
await user_coll.update_key(user.phone, user)
|
|
142
143
|
|
|
143
144
|
await user_coll.get_key("+447986123456") # => user
|
|
144
145
|
await user_coll.get_key("key missing") # => KeyError
|
|
@@ -154,6 +155,7 @@ async def main() -> None:
|
|
|
154
155
|
# Hint: The main purpose is tests.
|
|
155
156
|
await Scruby.napalm()
|
|
156
157
|
|
|
158
|
+
|
|
157
159
|
if __name__ == "__main__":
|
|
158
160
|
anyio.run(main)
|
|
159
161
|
```
|
|
@@ -175,8 +177,9 @@ from scruby import Scruby, constants
|
|
|
175
177
|
from pprint import pprint as pp
|
|
176
178
|
|
|
177
179
|
constants.DB_ROOT = "ScrubyDB" # By default = "ScrubyDB"
|
|
178
|
-
constants.
|
|
179
|
-
|
|
180
|
+
constants.HASH_REDUCE_LEFT = 6 # 256 branches in collection
|
|
181
|
+
# (main purpose is tests).
|
|
182
|
+
|
|
180
183
|
|
|
181
184
|
class User(BaseModel):
|
|
182
185
|
"""Model of User."""
|
|
@@ -186,6 +189,7 @@ class User(BaseModel):
|
|
|
186
189
|
email: EmailStr
|
|
187
190
|
phone: Annotated[PhoneNumber, PhoneNumberValidator(number_format="E164")]
|
|
188
191
|
|
|
192
|
+
|
|
189
193
|
async def main() -> None:
|
|
190
194
|
"""Example."""
|
|
191
195
|
# Get collection of `User`.
|
|
@@ -201,7 +205,7 @@ async def main() -> None:
|
|
|
201
205
|
)
|
|
202
206
|
|
|
203
207
|
# Add user to collection.
|
|
204
|
-
await user_coll.
|
|
208
|
+
await user_coll.add_key(user.phone, user)
|
|
205
209
|
|
|
206
210
|
# Find user by email.
|
|
207
211
|
user_details: User | None = user_coll.find_one(
|
|
@@ -225,6 +229,7 @@ async def main() -> None:
|
|
|
225
229
|
# Hint: The main purpose is tests.
|
|
226
230
|
await Scruby.napalm()
|
|
227
231
|
|
|
232
|
+
|
|
228
233
|
if __name__ == "__main__":
|
|
229
234
|
anyio.run(main)
|
|
230
235
|
```
|
|
@@ -246,8 +251,9 @@ from scruby import Scruby, constants
|
|
|
246
251
|
from pprint import pprint as pp
|
|
247
252
|
|
|
248
253
|
constants.DB_ROOT = "ScrubyDB" # By default = "ScrubyDB"
|
|
249
|
-
constants.
|
|
250
|
-
|
|
254
|
+
constants.HASH_REDUCE_LEFT = 6 # 256 branches in collection
|
|
255
|
+
# (main purpose is tests).
|
|
256
|
+
|
|
251
257
|
|
|
252
258
|
class User(BaseModel):
|
|
253
259
|
"""Model of User."""
|
|
@@ -257,6 +263,7 @@ class User(BaseModel):
|
|
|
257
263
|
email: EmailStr
|
|
258
264
|
phone: Annotated[PhoneNumber, PhoneNumberValidator(number_format="E164")]
|
|
259
265
|
|
|
266
|
+
|
|
260
267
|
async def main() -> None:
|
|
261
268
|
"""Example."""
|
|
262
269
|
# Get collection of `User`.
|
|
@@ -271,10 +278,10 @@ async def main() -> None:
|
|
|
271
278
|
email=f"John_Smith_{num}@gmail.com",
|
|
272
279
|
phone=f"+44798612345{num}",
|
|
273
280
|
)
|
|
274
|
-
await
|
|
281
|
+
await user_coll.add_key(user.phone, user)
|
|
275
282
|
|
|
276
283
|
# Find users by email.
|
|
277
|
-
users: list[User] | None = user_coll.
|
|
284
|
+
users: list[User] | None = user_coll.find_many(
|
|
278
285
|
filter_fn=lambda doc: doc.email == "John_Smith_5@gmail.com" or doc.email == "John_Smith_8@gmail.com",
|
|
279
286
|
)
|
|
280
287
|
if users is not None:
|
|
@@ -286,6 +293,7 @@ async def main() -> None:
|
|
|
286
293
|
# Hint: The main purpose is tests.
|
|
287
294
|
await Scruby.napalm()
|
|
288
295
|
|
|
296
|
+
|
|
289
297
|
if __name__ == "__main__":
|
|
290
298
|
anyio.run(main)
|
|
291
299
|
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
scruby/__init__.py,sha256=elrW_AWMyl3kuTpEqGPaYFSpF8iVzjpivF6MxVNlqoQ,855
|
|
2
|
+
scruby/aggregation.py,sha256=SYGcnMy2eq9vJb-pW3xR9LLAQIQ55TK-LGW_yKQ-7sU,3318
|
|
3
|
+
scruby/constants.py,sha256=KRx7naXDNzT1WVKiYXFJ8uYxS9-aSqoiilsa4qR6y1Y,976
|
|
4
|
+
scruby/db.py,sha256=Ml2A46bOX1P1sF4vKSyEFqklMAjoSpn1lGvj8VCtnSY,26323
|
|
5
|
+
scruby/errors.py,sha256=nMhSLAKo7F3lTB_lgOZ5ksMuBtA1ugHqF8iyp1EY-sY,1042
|
|
6
|
+
scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
scruby-0.17.0.dist-info/METADATA,sha256=8RMszCN_EnAzMTN3wpDrIh8BrrdlxYTX__pLyy6siz8,10079
|
|
8
|
+
scruby-0.17.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
9
|
+
scruby-0.17.0.dist-info/licenses/LICENSE,sha256=mS0Wz0yGNB63gEcWEnuIb_lldDYV0sjRaO-o_GL6CWE,1074
|
|
10
|
+
scruby-0.17.0.dist-info/RECORD,,
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Gennady Kostyunin
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Gennady Kostyunin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
scruby-0.9.3.dist-info/RECORD
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
scruby/__init__.py,sha256=wFwUS1KcLxfIopXOVS8gPue9fNzIIU2cVj_RgK5drz4,849
|
|
2
|
-
scruby/constants.py,sha256=GbB-O0qaVdi5EHUp-zRAppFXLR-oHxpXUFVAOCpS0C8,1022
|
|
3
|
-
scruby/db.py,sha256=reYCZduh4GAycS17oPw8BWoFd-M9A8N7BW_uPFwUd_w,10941
|
|
4
|
-
scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
scruby-0.9.3.dist-info/METADATA,sha256=YBlk8IR3bDVRV-XKLKEHkpd3Bir97OF0wyOe0jFDpR0,10828
|
|
6
|
-
scruby-0.9.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
-
scruby-0.9.3.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
|
|
8
|
-
scruby-0.9.3.dist-info/RECORD,,
|
|
File without changes
|