scruby 0.5.0__py3-none-any.whl → 0.6.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.

Potentially problematic release.


This version of scruby might be problematic. Click here for more details.

scruby/__init__.py CHANGED
@@ -3,11 +3,13 @@
3
3
  Scruby is a fast key-value storage library that provides an ordered mapping from string keys to string values.
4
4
  The library uses fractal-tree addressing.
5
5
 
6
- The maximum size of the database is 16**32=340282366920938463463374607431768211456 branches,
6
+ The database consists of collections.
7
+ The maximum size of the one collection is 16**8=4294967296 branches,
7
8
  each branch can store one or more keys.
8
9
 
9
- The value of any key can be obtained in 32 steps, thereby achieving high performance.
10
- There is no need to iterate through all the keys in search of the desired value.
10
+ The value of any key in collection can be obtained in 8 steps, thereby achieving high performance.
11
+
12
+ In the future, to search by value of key, the use of a quantum loop is supposed.
11
13
  """
12
14
 
13
15
  from __future__ import annotations
scruby/db.py CHANGED
@@ -4,7 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  __all__ = ("Scruby",)
6
6
 
7
- import hashlib
7
+ import contextlib
8
+ import zlib
8
9
  from shutil import rmtree
9
10
  from typing import TypeVar
10
11
 
@@ -29,19 +30,31 @@ class Scruby[T]:
29
30
  ) -> None:
30
31
  self.__class_model = class_model
31
32
 
33
+ def check_key(self, key: str) -> None:
34
+ """Check the key."""
35
+ if not isinstance(key, str):
36
+ raise KeyError("The key is not a type of `str`.")
37
+ if len(key) == 0:
38
+ raise KeyError("The key should not be empty.")
39
+
32
40
  async def get_leaf_path(self, key: str) -> Path:
33
41
  """Get the path to the database cell by key.
34
42
 
35
43
  Args:
36
44
  key: Key name.
37
45
  """
38
- # Key to md5 sum.
39
- key_md5: str = hashlib.md5(key.encode("utf-8")).hexdigest() # noqa: S324
40
- # Convert md5 sum in the segment of path.
41
- separated_md5: str = "/".join(list(key_md5))
46
+ self.check_key(key)
47
+ # Key to crc32 sum.
48
+ key_crc32: str = f"{zlib.crc32(key.encode('utf-8')):08x}"
49
+ # Convert crc32 sum in the segment of path.
50
+ separated_crc32: str = "/".join(list(key_crc32))
42
51
  # The path of the branch to the database.
43
52
  branch_path: Path = Path(
44
- *(constants.DB_ROOT, self.__class_model.__name__, separated_md5),
53
+ *(
54
+ constants.DB_ROOT,
55
+ self.__class_model.__name__,
56
+ separated_crc32,
57
+ ),
45
58
  )
46
59
  # If the branch does not exist, need to create it.
47
60
  if not await branch_path.exists():
@@ -127,7 +140,8 @@ class Scruby[T]:
127
140
  return
128
141
  raise KeyError()
129
142
 
130
- async def napalm(self) -> None:
143
+ @classmethod
144
+ async def napalm(cls) -> None:
131
145
  """Asynchronous method for full database deletion (Arg: db_name).
132
146
 
133
147
  The main purpose is tests.
@@ -135,5 +149,6 @@ class Scruby[T]:
135
149
  Warning:
136
150
  - `Be careful, this will remove all keys.`
137
151
  """
138
- await to_thread.run_sync(rmtree, constants.DB_ROOT)
152
+ with contextlib.suppress(FileNotFoundError):
153
+ await to_thread.run_sync(rmtree, constants.DB_ROOT)
139
154
  return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scruby
3
- Version: 0.5.0
3
+ Version: 0.6.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
@@ -27,7 +27,9 @@ Classifier: Typing :: Typed
27
27
  Requires-Python: <4.0,>=3.12
28
28
  Requires-Dist: anyio>=4.10.0
29
29
  Requires-Dist: orjson>=3.11.3
30
- Requires-Dist: pydantic>=2.11.7
30
+ Requires-Dist: phonenumbers>=9.0.13
31
+ Requires-Dist: pydantic-extra-types>=2.10.5
32
+ Requires-Dist: pydantic[email]>=2.11.7
31
33
  Description-Content-Type: text/markdown
32
34
 
33
35
  <div align="center">
@@ -64,15 +66,15 @@ Description-Content-Type: text/markdown
64
66
  </p>
65
67
  <p align="center">
66
68
  Scruby is a fast key-value storage library that provides an ordered mapping from string keys to string values.
67
- <br>
68
69
  The library uses fractal-tree addressing.
69
70
  <br>
70
- The maximum size of the database is 16**32=340282366920938463463374607431768211456 branches,
71
+ The database consists of collections.
72
+ The maximum size of the one collection is 16**8=4294967296 branches,
71
73
  each branch can store one or more keys.
72
74
  <br>
73
- The value of any key can be obtained in 32 steps, thereby achieving high performance.
75
+ The value of any key in collection can be obtained in 8 steps, thereby achieving high performance.
74
76
  <br>
75
- There is no need to iterate through all the keys in search of the desired value.
77
+ In the future, to search by value of key, the use of a quantum loop is supposed.
76
78
  </p>
77
79
  </p>
78
80
  </div>
@@ -96,23 +98,24 @@ uv add scruby
96
98
  ```python
97
99
  import anyio
98
100
  import datetime
99
- from pydantic import BaseModel
101
+ from pydantic import BaseModel, EmailStr
102
+ from pydantic_extra_types.phone_numbers import PhoneNumber
100
103
  from scruby import Scruby, constants
101
104
 
102
105
  constants.DB_ROOT = "ScrubyDB" # By default = "ScrubyDB"
103
106
 
104
107
  class User(BaseModel):
105
108
  """Model of User."""
106
-
107
109
  first_name: str
108
110
  last_name: str
109
111
  birthday: datetime.datetime
110
- email: str
111
- phone: str
112
+ email: EmailStr
113
+ phone: PhoneNumber
112
114
 
113
115
  async def main() -> None:
114
116
  """Example."""
115
- db = Scruby(User)
117
+ # Get collection of `User`.
118
+ user_coll = Scruby(User)
116
119
 
117
120
  user = User(
118
121
  first_name="John",
@@ -122,23 +125,21 @@ async def main() -> None:
122
125
  phone="+447986123456",
123
126
  )
124
127
 
125
- await db.set_key("+447986123456", user)
128
+ await user_coll.set_key("+447986123456", user)
126
129
 
127
- await db.get_key("+447986123456") # => user
128
- await db.get_key("key missing") # => KeyError
130
+ await user_coll.get_key("+447986123456") # => user
131
+ await user_coll.get_key("key missing") # => KeyError
129
132
 
130
- await db.has_key("+447986123456") # => True
131
- await db.has_key("key missing") # => False
133
+ await user_coll.has_key("+447986123456") # => True
134
+ await user_coll.has_key("key missing") # => False
132
135
 
133
- await db.delete_key("+447986123456")
134
- await db.delete_key("+447986123456") # => KeyError
135
- await db.delete_key("key missing") # => KeyError
136
+ await user_coll.delete_key("+447986123456")
137
+ await user_coll.delete_key("+447986123456") # => KeyError
138
+ await user_coll.delete_key("key missing") # => KeyError
136
139
 
137
140
  # Full database deletion.
138
141
  # Hint: The main purpose is tests.
139
- await db.napalm()
140
- await db.napalm() # => FileNotFoundError
141
-
142
+ await Scruby.napalm()
142
143
 
143
144
  if __name__ == "__main__":
144
145
  anyio.run(main)
@@ -0,0 +1,8 @@
1
+ scruby/__init__.py,sha256=Mvy-90k-kNUAlYA7xuCEIT1uC8u5pepuDxGy6DglCxU,689
2
+ scruby/constants.py,sha256=kwF0FIbeChBxsNxOCQhMsDEn1lakD7MIQKJ-PHYeSAo,328
3
+ scruby/db.py,sha256=Xn7AWXly8nubvWqsRrJYpvozUHB1CXNineizVK6GNEw,4854
4
+ scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ scruby-0.6.0.dist-info/METADATA,sha256=2mxPkFwKcU2V-Mw6nz_fru7xo-TVdugS5XUPNYoJONg,6751
6
+ scruby-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ scruby-0.6.0.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
8
+ scruby-0.6.0.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- scruby/__init__.py,sha256=LnHBN1pIOtT89baSQoknQwYI1cy-hmN1Lo0k8o1Ms48,659
2
- scruby/constants.py,sha256=kwF0FIbeChBxsNxOCQhMsDEn1lakD7MIQKJ-PHYeSAo,328
3
- scruby/db.py,sha256=iG1D4-ncVrVysp7OXH-eZksnNacjNna4_8nUbMkWnSE,4409
4
- scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- scruby-0.5.0.dist-info/METADATA,sha256=6V1NV3KWNRsc2Gb2cZbBQ4VsLYbIDMWkCiM9CjkJyxo,6509
6
- scruby-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- scruby-0.5.0.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
8
- scruby-0.5.0.dist-info/RECORD,,
File without changes