scruby 0.3.0__py3-none-any.whl → 0.5.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
@@ -12,6 +12,10 @@ There is no need to iterate through all the keys in search of the desired value.
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
- __all__ = ("Scruby",)
15
+ __all__ = (
16
+ "Scruby",
17
+ "constants",
18
+ )
16
19
 
20
+ from scruby import constants
17
21
  from scruby.db import Scruby
scruby/constants.py ADDED
@@ -0,0 +1,11 @@
1
+ """Constant variables.
2
+
3
+ The module contains the following variables:
4
+
5
+ - `DB_ROOT` - Path to root directory of database. By default = "ScrubyDB" (in root of project).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ # Path to root directory of database. By default = "ScrubyDB" (in root of project).
11
+ DB_ROOT: str = "ScrubyDB"
scruby/db.py CHANGED
@@ -1,19 +1,4 @@
1
- """Creation and management of the database.
2
-
3
- Examples:
4
- >>> from scruby import Scruby
5
- >>> db = Scruby()
6
- >>> await db.set_key("key name", "Some text")
7
- None
8
- >>> await db.get_key("key name")
9
- "Some text"
10
- >>> await db.has_key("key name")
11
- True
12
- >>> await db.delete_key("key name")
13
- None
14
- >>> await db.napalm()
15
- None
16
- """
1
+ """Creation and management of the database."""
17
2
 
18
3
  from __future__ import annotations
19
4
 
@@ -21,46 +6,28 @@ __all__ = ("Scruby",)
21
6
 
22
7
  import hashlib
23
8
  from shutil import rmtree
24
- from typing import Literal
9
+ from typing import TypeVar
25
10
 
26
11
  import orjson
27
12
  from anyio import Path, to_thread
28
13
 
29
- type ValueOfKey = str | int | float | list | dict | Literal[True] | Literal[False] | None
14
+ from scruby import constants
30
15
 
16
+ T = TypeVar("T")
31
17
 
32
- class Scruby:
33
- """Creation and management of the database.
34
18
 
35
- Examples:
36
- >>> from scruby import Scruby
37
- >>> db = Scruby()
38
- >>> await db.set_key("key name", "Some text")
39
- None
40
- >>> await db.get_key("key name")
41
- "Some text"
42
- >>> await db.has_key("key name")
43
- True
44
- >>> await db.delete_key("key name")
45
- None
46
- >>> await db.napalm()
47
- None
19
+ class Scruby[T]:
20
+ """Creation and management of the database.
48
21
 
49
22
  Args:
50
- db_path: Path to root directory of databases. Defaule by = "ScrubyDB" (in root of project)
23
+ class_model: Class of Model (Pydantic).
51
24
  """
52
25
 
53
26
  def __init__( # noqa: D107
54
27
  self,
55
- db_path: str = "ScrubyDB",
28
+ class_model: T,
56
29
  ) -> None:
57
- super().__init__()
58
- self.__db_path = db_path
59
-
60
- @property
61
- def db_path(self) -> str:
62
- """Get database name."""
63
- return self.__db_path
30
+ self.__class_model = class_model
64
31
 
65
32
  async def get_leaf_path(self, key: str) -> Path:
66
33
  """Get the path to the database cell by key.
@@ -71,10 +38,10 @@ class Scruby:
71
38
  # Key to md5 sum.
72
39
  key_md5: str = hashlib.md5(key.encode("utf-8")).hexdigest() # noqa: S324
73
40
  # Convert md5 sum in the segment of path.
74
- segment_path_md5: str = "/".join(list(key_md5))
41
+ separated_md5: str = "/".join(list(key_md5))
75
42
  # The path of the branch to the database.
76
43
  branch_path: Path = Path(
77
- *(self.__db_path, segment_path_md5),
44
+ *(constants.DB_ROOT, self.__class_model.__name__, separated_md5),
78
45
  )
79
46
  # If the branch does not exist, need to create it.
80
47
  if not await branch_path.exists():
@@ -86,46 +53,31 @@ class Scruby:
86
53
  async def set_key(
87
54
  self,
88
55
  key: str,
89
- value: ValueOfKey,
56
+ value: T,
90
57
  ) -> None:
91
58
  """Asynchronous method for adding and updating keys to database.
92
59
 
93
- Examples:
94
- >>> from scruby import Scruby
95
- >>> db = Scruby()
96
- >>> await db.set_key("key name", "Some text")
97
- None
98
-
99
60
  Args:
100
61
  key: Key name.
101
62
  value: Value of key.
102
63
  """
103
64
  # The path to the database cell.
104
65
  leaf_path: Path = await self.get_leaf_path(key)
66
+ value_json: str = value.model_dump_json()
105
67
  # Write key-value to the database.
106
68
  if await leaf_path.exists():
107
69
  # Add new key or update existing.
108
70
  data_json: bytes = await leaf_path.read_bytes()
109
71
  data: dict = orjson.loads(data_json) or {}
110
- data[key] = value
72
+ data[key] = value_json
111
73
  await leaf_path.write_bytes(orjson.dumps(data))
112
74
  else:
113
75
  # Add new key to a blank leaf.
114
- await leaf_path.write_bytes(data=orjson.dumps({key: value}))
76
+ await leaf_path.write_bytes(orjson.dumps({key: value_json}))
115
77
 
116
- async def get_key(self, key: str) -> ValueOfKey:
78
+ async def get_key(self, key: str) -> T:
117
79
  """Asynchronous method for getting key from database.
118
80
 
119
- Examples:
120
- >>> from scruby import Scruby
121
- >>> db = Scruby()
122
- >>> await db.set_key("key name", "Some text")
123
- None
124
- >>> await db.get_key("key name")
125
- "Some text"
126
- >>> await db.get_key("key missing")
127
- KeyError
128
-
129
81
  Args:
130
82
  key: Key name.
131
83
  """
@@ -135,22 +87,13 @@ class Scruby:
135
87
  if await leaf_path.exists():
136
88
  data_json: bytes = await leaf_path.read_bytes()
137
89
  data: dict = orjson.loads(data_json) or {}
138
- return data[key]
90
+ obj: T = self.__class_model.model_validate_json(data[key])
91
+ return obj
139
92
  raise KeyError()
140
93
 
141
94
  async def has_key(self, key: str) -> bool:
142
95
  """Asynchronous method for checking presence of key in database.
143
96
 
144
- Examples:
145
- >>> from scruby import Scruby
146
- >>> db = Scruby()
147
- >>> await db.set_key("key name", "Some text")
148
- None
149
- >>> await db.has_key("key name")
150
- True
151
- >>> await db.has_key("key missing")
152
- False
153
-
154
97
  Args:
155
98
  key: Key name.
156
99
  """
@@ -170,16 +113,6 @@ class Scruby:
170
113
  async def delete_key(self, key: str) -> None:
171
114
  """Asynchronous method for deleting key from database.
172
115
 
173
- Examples:
174
- >>> from scruby import Scruby
175
- >>> db = Scruby()
176
- >>> await db.set_key("key name", "Some text")
177
- None
178
- >>> await db.delete_key("key name")
179
- None
180
- >>> await db.delete_key("key missing")
181
- KeyError
182
-
183
116
  Args:
184
117
  key: Key name.
185
118
  """
@@ -195,20 +128,12 @@ class Scruby:
195
128
  raise KeyError()
196
129
 
197
130
  async def napalm(self) -> None:
198
- """Asynchronous method for full database deletion (Arg: db_path).
131
+ """Asynchronous method for full database deletion (Arg: db_name).
132
+
133
+ The main purpose is tests.
199
134
 
200
135
  Warning:
201
136
  - `Be careful, this will remove all keys.`
202
-
203
- Examples:
204
- >>> from scruby import Scruby
205
- >>> db = Scruby()
206
- >>> await db.set_key("key name", "Some text")
207
- None
208
- >>> await db.napalm()
209
- None
210
- >>> await db.napalm()
211
- FileNotFoundError
212
137
  """
213
- await to_thread.run_sync(rmtree, self.__db_path)
138
+ await to_thread.run_sync(rmtree, constants.DB_ROOT)
214
139
  return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scruby
3
- Version: 0.3.0
3
+ Version: 0.5.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
@@ -11,7 +11,7 @@ Author-email: kebasyaty <kebasyaty@gmail.com>
11
11
  License-Expression: MIT
12
12
  License-File: LICENSE
13
13
  Keywords: database,db,scruby,store
14
- Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Development Status :: 4 - Beta
15
15
  Classifier: Intended Audience :: Developers
16
16
  Classifier: License :: OSI Approved :: MIT License
17
17
  Classifier: Operating System :: MacOS :: MacOS X
@@ -26,7 +26,8 @@ Classifier: Topic :: Database
26
26
  Classifier: Typing :: Typed
27
27
  Requires-Python: <4.0,>=3.12
28
28
  Requires-Dist: anyio>=4.10.0
29
- Requires-Dist: orjson>=3.11.2
29
+ Requires-Dist: orjson>=3.11.3
30
+ Requires-Dist: pydantic>=2.11.7
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  <div align="center">
@@ -94,36 +95,47 @@ uv add scruby
94
95
 
95
96
  ```python
96
97
  import anyio
97
- from scruby import Scruby
98
+ import datetime
99
+ from pydantic import BaseModel
100
+ from scruby import Scruby, constants
98
101
 
102
+ constants.DB_ROOT = "ScrubyDB" # By default = "ScrubyDB"
103
+
104
+ class User(BaseModel):
105
+ """Model of User."""
106
+
107
+ first_name: str
108
+ last_name: str
109
+ birthday: datetime.datetime
110
+ email: str
111
+ phone: str
99
112
 
100
113
  async def main() -> None:
101
114
  """Example."""
115
+ db = Scruby(User)
102
116
 
103
- db = Scruby()
104
- await db.set_key("key name", "Some text")
105
- # Update key
106
- await db.set_key("key name", "Some new text")
117
+ user = User(
118
+ first_name="John",
119
+ last_name="Smith",
120
+ birthday=datetime.datetime(1970, 1, 1),
121
+ email="John_Smith@gmail.com",
122
+ phone="+447986123456",
123
+ )
107
124
 
108
- user_details = {
109
- "first name": "John",
110
- "last name": "Smith",
111
- "email": "John_Smith@gmail.com",
112
- "phone": "+447986123456",
113
- }
114
- await db.set_key("+447986123456", user_details)
125
+ await db.set_key("+447986123456", user)
115
126
 
116
- await db.get_key("key name") # => "Some text"
127
+ await db.get_key("+447986123456") # => user
117
128
  await db.get_key("key missing") # => KeyError
118
129
 
119
- await db.has_key("key name") # => True
130
+ await db.has_key("+447986123456") # => True
120
131
  await db.has_key("key missing") # => False
121
132
 
122
- await db.delete_key("key name")
123
- await db.delete_key("key name") # => KeyError
133
+ await db.delete_key("+447986123456")
134
+ await db.delete_key("+447986123456") # => KeyError
124
135
  await db.delete_key("key missing") # => KeyError
125
136
 
126
137
  # Full database deletion.
138
+ # Hint: The main purpose is tests.
127
139
  await db.napalm()
128
140
  await db.napalm() # => FileNotFoundError
129
141
 
@@ -0,0 +1,8 @@
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,,
@@ -1,7 +0,0 @@
1
- scruby/__init__.py,sha256=TCxUjBI5A0KZcwvfmgaBVl8ScuzzOVvALl_T4iqSR9c,603
2
- scruby/db.py,sha256=otENL-t7ie_8Fgzcteh2WsXFPu9pM4DBUdO_2GB1vwk,6565
3
- scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- scruby-0.3.0.dist-info/METADATA,sha256=Dkz32lF7SmIWBEdXNhuhHQkYunAas6A84cEaVu08bYM,6256
5
- scruby-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
- scruby-0.3.0.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
7
- scruby-0.3.0.dist-info/RECORD,,
File without changes