scruby 0.10.3__py3-none-any.whl → 0.11.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/constants.py +3 -3
- scruby/db.py +145 -47
- scruby/errors.py +6 -3
- {scruby-0.10.3.dist-info → scruby-0.11.0.dist-info}/METADATA +4 -4
- scruby-0.11.0.dist-info/RECORD +9 -0
- scruby-0.10.3.dist-info/RECORD +0 -9
- {scruby-0.10.3.dist-info → scruby-0.11.0.dist-info}/WHEEL +0 -0
- {scruby-0.10.3.dist-info → scruby-0.11.0.dist-info}/licenses/LICENSE +0 -0
scruby/constants.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The module contains the following variables:
|
|
4
4
|
|
|
5
5
|
- `DB_ROOT` - Path to root directory of database. `By default = "ScrubyDB"` (*in root of project*).
|
|
6
|
-
- `
|
|
6
|
+
- `HASH_REDUCE_LEFT` - The length of the hash reduction on the left side.
|
|
7
7
|
- `0` - 4294967296 branches in collection (by default).
|
|
8
8
|
- `2` - 16777216 branches in collectionю
|
|
9
9
|
- `4` - 65536 branches in collectionю
|
|
@@ -14,7 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
|
|
15
15
|
__all__ = (
|
|
16
16
|
"DB_ROOT",
|
|
17
|
-
"
|
|
17
|
+
"HASH_REDUCE_LEFT",
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
from typing import Literal
|
|
@@ -28,4 +28,4 @@ DB_ROOT: str = "ScrubyDB"
|
|
|
28
28
|
# 2 = 16777216 branches in collectionю
|
|
29
29
|
# 4 = 65536 branches in collectionю
|
|
30
30
|
# 6 = 256 branches in collection (main purpose is tests).
|
|
31
|
-
|
|
31
|
+
HASH_REDUCE_LEFT: Literal[0, 2, 4, 6] = 0
|
scruby/db.py
CHANGED
|
@@ -11,7 +11,7 @@ import zlib
|
|
|
11
11
|
from collections.abc import Callable
|
|
12
12
|
from pathlib import Path as SyncPath
|
|
13
13
|
from shutil import rmtree
|
|
14
|
-
from typing import Any,
|
|
14
|
+
from typing import Any, Never, TypeVar, assert_never
|
|
15
15
|
|
|
16
16
|
import orjson
|
|
17
17
|
from anyio import Path, to_thread
|
|
@@ -27,9 +27,6 @@ T = TypeVar("T")
|
|
|
27
27
|
class _Meta(BaseModel):
|
|
28
28
|
"""Metadata of Collection."""
|
|
29
29
|
|
|
30
|
-
db_root: str
|
|
31
|
-
model_name: str
|
|
32
|
-
length_reduction_hash: int
|
|
33
30
|
counter_documents: int
|
|
34
31
|
|
|
35
32
|
|
|
@@ -47,19 +44,19 @@ class Scruby[T]:
|
|
|
47
44
|
self.__meta = _Meta
|
|
48
45
|
self.__class_model = class_model
|
|
49
46
|
self.__db_root = constants.DB_ROOT
|
|
50
|
-
self.
|
|
47
|
+
self.__hash_reduce_left = constants.HASH_REDUCE_LEFT
|
|
51
48
|
# The maximum number of keys.
|
|
52
|
-
match self.
|
|
49
|
+
match self.__hash_reduce_left:
|
|
53
50
|
case 0:
|
|
54
|
-
self.
|
|
51
|
+
self.__max_branch_number = 4294967296
|
|
55
52
|
case 2:
|
|
56
|
-
self.
|
|
53
|
+
self.__max_branch_number = 16777216
|
|
57
54
|
case 4:
|
|
58
|
-
self.
|
|
55
|
+
self.__max_branch_number = 65536
|
|
59
56
|
case 6:
|
|
60
|
-
self.
|
|
57
|
+
self.__max_branch_number = 256
|
|
61
58
|
case _ as unreachable:
|
|
62
|
-
msg: str = f"{unreachable} - Unacceptable value for
|
|
59
|
+
msg: str = f"{unreachable} - Unacceptable value for HASH_REDUCE_LEFT."
|
|
63
60
|
logger.critical(msg)
|
|
64
61
|
assert_never(Never(unreachable))
|
|
65
62
|
# 1.Create metadata if absent.
|
|
@@ -71,8 +68,8 @@ class Scruby[T]:
|
|
|
71
68
|
|
|
72
69
|
This method is for internal use.
|
|
73
70
|
"""
|
|
74
|
-
|
|
75
|
-
key_as_hash: str = f"{
|
|
71
|
+
branch_number: int = 0
|
|
72
|
+
key_as_hash: str = f"{branch_number:08x}"[self.__hash_reduce_left :]
|
|
76
73
|
separated_hash: str = "/".join(list(key_as_hash))
|
|
77
74
|
branch_path = SyncPath(
|
|
78
75
|
*(
|
|
@@ -84,9 +81,6 @@ class Scruby[T]:
|
|
|
84
81
|
if not branch_path.exists():
|
|
85
82
|
branch_path.mkdir(parents=True)
|
|
86
83
|
meta = _Meta(
|
|
87
|
-
db_root=self.__db_root,
|
|
88
|
-
model_name=self.__class_model.__name__,
|
|
89
|
-
length_reduction_hash=self.__length_reduction_hash,
|
|
90
84
|
counter_documents=0,
|
|
91
85
|
)
|
|
92
86
|
meta_json = meta.model_dump_json()
|
|
@@ -98,9 +92,9 @@ class Scruby[T]:
|
|
|
98
92
|
|
|
99
93
|
This method is for internal use.
|
|
100
94
|
"""
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
separated_hash: str = "/".join(list(
|
|
95
|
+
branch_number: int = 0
|
|
96
|
+
branch_number_as_hash: str = f"{branch_number:08x}"[self.__hash_reduce_left :]
|
|
97
|
+
separated_hash: str = "/".join(list(branch_number_as_hash))
|
|
104
98
|
return Path(
|
|
105
99
|
*(
|
|
106
100
|
self.__db_root,
|
|
@@ -129,16 +123,43 @@ class Scruby[T]:
|
|
|
129
123
|
meta_json = meta.model_dump_json()
|
|
130
124
|
await meta_path.write_text(meta_json, "utf-8")
|
|
131
125
|
|
|
132
|
-
async def _counter_documents(self,
|
|
126
|
+
async def _counter_documents(self, number: int) -> None:
|
|
127
|
+
"""Asynchronous method for management of documents in metadata of collection.
|
|
128
|
+
|
|
129
|
+
This method is for internal use.
|
|
130
|
+
"""
|
|
131
|
+
meta_path = await self._get_meta_path()
|
|
132
|
+
meta_json = await meta_path.read_text("utf-8")
|
|
133
|
+
meta: _Meta = self.__meta.model_validate_json(meta_json)
|
|
134
|
+
meta.counter_documents += number
|
|
135
|
+
if meta.counter_documents < 0:
|
|
136
|
+
meta.counter_documents = 0
|
|
137
|
+
meta_json = meta.model_dump_json()
|
|
138
|
+
await meta_path.write_text(meta_json, "utf-8")
|
|
139
|
+
|
|
140
|
+
def _sync_counter_documents(self, number: int) -> None:
|
|
133
141
|
"""Management of documents in metadata of collection.
|
|
134
142
|
|
|
135
143
|
This method is for internal use.
|
|
136
144
|
"""
|
|
137
|
-
|
|
138
|
-
|
|
145
|
+
branch_number: int = 0
|
|
146
|
+
branch_number_as_hash: str = f"{branch_number:08x}"[self.__hash_reduce_left :]
|
|
147
|
+
separated_hash: str = "/".join(list(branch_number_as_hash))
|
|
148
|
+
meta_path = SyncPath(
|
|
149
|
+
*(
|
|
150
|
+
self.__db_root,
|
|
151
|
+
self.__class_model.__name__,
|
|
152
|
+
separated_hash,
|
|
153
|
+
"meta.json",
|
|
154
|
+
),
|
|
155
|
+
)
|
|
156
|
+
meta_json = meta_path.read_text("utf-8")
|
|
157
|
+
meta: _Meta = self.__meta.model_validate_json(meta_json)
|
|
158
|
+
meta.counter_documents += number
|
|
139
159
|
if meta.counter_documents < 0:
|
|
140
160
|
meta.counter_documents = 0
|
|
141
|
-
|
|
161
|
+
meta_json = meta.model_dump_json()
|
|
162
|
+
meta_path.write_text(meta_json, "utf-8")
|
|
142
163
|
|
|
143
164
|
async def _get_leaf_path(self, key: str) -> Path:
|
|
144
165
|
"""Asynchronous method for getting path to collection cell by key.
|
|
@@ -155,7 +176,7 @@ class Scruby[T]:
|
|
|
155
176
|
logger.error("The key should not be empty.")
|
|
156
177
|
raise KeyError("The key should not be empty.")
|
|
157
178
|
# Key to crc32 sum.
|
|
158
|
-
key_as_hash: str = f"{zlib.crc32(key.encode('utf-8')):08x}"[self.
|
|
179
|
+
key_as_hash: str = f"{zlib.crc32(key.encode('utf-8')):08x}"[self.__hash_reduce_left :]
|
|
159
180
|
# Convert crc32 sum in the segment of path.
|
|
160
181
|
separated_hash: str = "/".join(list(key_as_hash))
|
|
161
182
|
# The path of the branch to the database.
|
|
@@ -273,18 +294,18 @@ class Scruby[T]:
|
|
|
273
294
|
|
|
274
295
|
@staticmethod
|
|
275
296
|
def _task_find(
|
|
276
|
-
|
|
297
|
+
branch_number: int,
|
|
277
298
|
filter_fn: Callable,
|
|
278
|
-
|
|
299
|
+
hash_reduce_left: str,
|
|
279
300
|
db_root: str,
|
|
280
301
|
class_model: T,
|
|
281
302
|
) -> dict[str, Any] | None:
|
|
282
|
-
"""Task for
|
|
303
|
+
"""Task for find documents.
|
|
283
304
|
|
|
284
305
|
This method is for internal use.
|
|
285
306
|
"""
|
|
286
|
-
|
|
287
|
-
separated_hash: str = "/".join(list(
|
|
307
|
+
branch_number_as_hash: str = f"{branch_number:08x}"[hash_reduce_left:]
|
|
308
|
+
separated_hash: str = "/".join(list(branch_number_as_hash))
|
|
288
309
|
leaf_path: SyncPath = SyncPath(
|
|
289
310
|
*(
|
|
290
311
|
db_root,
|
|
@@ -308,7 +329,7 @@ class Scruby[T]:
|
|
|
308
329
|
max_workers: int | None = None,
|
|
309
330
|
timeout: float | None = None,
|
|
310
331
|
) -> T | None:
|
|
311
|
-
"""
|
|
332
|
+
"""Finds a single document matching the filter.
|
|
312
333
|
|
|
313
334
|
The search is based on the effect of a quantum loop.
|
|
314
335
|
The search effectiveness depends on the number of processor threads.
|
|
@@ -322,18 +343,18 @@ class Scruby[T]:
|
|
|
322
343
|
timeout: The number of seconds to wait for the result if the future isn't done.
|
|
323
344
|
If None, then there is no limit on the wait time.
|
|
324
345
|
"""
|
|
325
|
-
|
|
346
|
+
branch_numbers: range = range(1, self.__max_branch_number)
|
|
326
347
|
search_task_fn: Callable = self._task_find
|
|
327
|
-
|
|
348
|
+
hash_reduce_left: int = self.__hash_reduce_left
|
|
328
349
|
db_root: str = self.__db_root
|
|
329
350
|
class_model: T = self.__class_model
|
|
330
351
|
with concurrent.futures.ThreadPoolExecutor(max_workers) as executor:
|
|
331
|
-
for
|
|
352
|
+
for branch_number in branch_numbers:
|
|
332
353
|
future = executor.submit(
|
|
333
354
|
search_task_fn,
|
|
334
|
-
|
|
355
|
+
branch_number,
|
|
335
356
|
filter_fn,
|
|
336
|
-
|
|
357
|
+
hash_reduce_left,
|
|
337
358
|
db_root,
|
|
338
359
|
class_model,
|
|
339
360
|
)
|
|
@@ -342,14 +363,14 @@ class Scruby[T]:
|
|
|
342
363
|
return doc
|
|
343
364
|
return None
|
|
344
365
|
|
|
345
|
-
def
|
|
366
|
+
def find_many(
|
|
346
367
|
self,
|
|
347
368
|
filter_fn: Callable,
|
|
348
369
|
db_query_docs_limit: int = 1000,
|
|
349
370
|
max_workers: int | None = None,
|
|
350
371
|
timeout: float | None = None,
|
|
351
372
|
) -> list[T] | None:
|
|
352
|
-
"""
|
|
373
|
+
"""Finds one or more documents matching the filter.
|
|
353
374
|
|
|
354
375
|
The search is based on the effect of a quantum loop.
|
|
355
376
|
The search effectiveness depends on the number of processor threads.
|
|
@@ -364,22 +385,22 @@ class Scruby[T]:
|
|
|
364
385
|
timeout: The number of seconds to wait for the result if the future isn't done.
|
|
365
386
|
If None, then there is no limit on the wait time.
|
|
366
387
|
"""
|
|
367
|
-
|
|
388
|
+
branch_numbers: range = range(1, self.__max_branch_number)
|
|
368
389
|
search_task_fn: Callable = self._task_find
|
|
369
|
-
|
|
390
|
+
hash_reduce_left: int = self.__hash_reduce_left
|
|
370
391
|
db_root: str = self.__db_root
|
|
371
392
|
class_model: T = self.__class_model
|
|
372
393
|
counter: int = 0
|
|
373
394
|
with concurrent.futures.ThreadPoolExecutor(max_workers) as executor:
|
|
374
395
|
results = []
|
|
375
|
-
for
|
|
396
|
+
for branch_number in branch_numbers:
|
|
376
397
|
if counter == db_query_docs_limit:
|
|
377
398
|
break
|
|
378
399
|
future = executor.submit(
|
|
379
400
|
search_task_fn,
|
|
380
|
-
|
|
401
|
+
branch_number,
|
|
381
402
|
filter_fn,
|
|
382
|
-
|
|
403
|
+
hash_reduce_left,
|
|
383
404
|
db_root,
|
|
384
405
|
class_model,
|
|
385
406
|
)
|
|
@@ -422,22 +443,99 @@ class Scruby[T]:
|
|
|
422
443
|
timeout: The number of seconds to wait for the result if the future isn't done.
|
|
423
444
|
If None, then there is no limit on the wait time.
|
|
424
445
|
"""
|
|
425
|
-
|
|
446
|
+
branch_numbers: range = range(1, self.__max_branch_number)
|
|
426
447
|
search_task_fn: Callable = self._task_find
|
|
427
|
-
|
|
448
|
+
hash_reduce_left: int = self.__hash_reduce_left
|
|
428
449
|
db_root: str = self.__db_root
|
|
429
450
|
class_model: T = self.__class_model
|
|
430
451
|
counter: int = 0
|
|
431
452
|
with concurrent.futures.ThreadPoolExecutor(max_workers) as executor:
|
|
432
|
-
for
|
|
453
|
+
for branch_number in branch_numbers:
|
|
433
454
|
future = executor.submit(
|
|
434
455
|
search_task_fn,
|
|
435
|
-
|
|
456
|
+
branch_number,
|
|
436
457
|
filter_fn,
|
|
437
|
-
|
|
458
|
+
hash_reduce_left,
|
|
438
459
|
db_root,
|
|
439
460
|
class_model,
|
|
440
461
|
)
|
|
441
462
|
if future.result(timeout) is not None:
|
|
442
463
|
counter += 1
|
|
443
464
|
return counter
|
|
465
|
+
|
|
466
|
+
@staticmethod
|
|
467
|
+
def _task_delete(
|
|
468
|
+
branch_number: int,
|
|
469
|
+
filter_fn: Callable,
|
|
470
|
+
hash_reduce_left: str,
|
|
471
|
+
db_root: str,
|
|
472
|
+
class_model: T,
|
|
473
|
+
) -> int:
|
|
474
|
+
"""Task for find and delete documents.
|
|
475
|
+
|
|
476
|
+
This method is for internal use.
|
|
477
|
+
"""
|
|
478
|
+
branch_number_as_hash: str = f"{branch_number:08x}"[hash_reduce_left:]
|
|
479
|
+
separated_hash: str = "/".join(list(branch_number_as_hash))
|
|
480
|
+
leaf_path: SyncPath = SyncPath(
|
|
481
|
+
*(
|
|
482
|
+
db_root,
|
|
483
|
+
class_model.__name__,
|
|
484
|
+
separated_hash,
|
|
485
|
+
"leaf.json",
|
|
486
|
+
),
|
|
487
|
+
)
|
|
488
|
+
counter: int = 0
|
|
489
|
+
if leaf_path.exists():
|
|
490
|
+
data_json: bytes = leaf_path.read_bytes()
|
|
491
|
+
data: dict[str, str] = orjson.loads(data_json) or {}
|
|
492
|
+
new_data: dict[str, str] = {}
|
|
493
|
+
for key, val in data.items():
|
|
494
|
+
doc = class_model.model_validate_json(val)
|
|
495
|
+
if filter_fn(doc):
|
|
496
|
+
counter -= 1
|
|
497
|
+
else:
|
|
498
|
+
new_data[key] = val
|
|
499
|
+
leaf_path.write_bytes(orjson.dumps(new_data))
|
|
500
|
+
return counter
|
|
501
|
+
|
|
502
|
+
def find_many_and_delete(
|
|
503
|
+
self,
|
|
504
|
+
filter_fn: Callable,
|
|
505
|
+
max_workers: int | None = None,
|
|
506
|
+
timeout: float | None = None,
|
|
507
|
+
) -> int:
|
|
508
|
+
"""Finds one or more documents matching the filter and deletes their.
|
|
509
|
+
|
|
510
|
+
The search is based on the effect of a quantum loop.
|
|
511
|
+
The search effectiveness depends on the number of processor threads.
|
|
512
|
+
Ideally, hundreds and even thousands of threads are required.
|
|
513
|
+
|
|
514
|
+
Args:
|
|
515
|
+
filter_fn: A function that execute the conditions of filtering.
|
|
516
|
+
max_workers: The maximum number of processes that can be used to
|
|
517
|
+
execute the given calls. If None or not given then as many
|
|
518
|
+
worker processes will be created as the machine has processors.
|
|
519
|
+
timeout: The number of seconds to wait for the result if the future isn't done.
|
|
520
|
+
If None, then there is no limit on the wait time.
|
|
521
|
+
"""
|
|
522
|
+
branch_numbers: range = range(1, self.__max_branch_number)
|
|
523
|
+
search_task_fn: Callable = self._task_delete
|
|
524
|
+
hash_reduce_left: int = self.__hash_reduce_left
|
|
525
|
+
db_root: str = self.__db_root
|
|
526
|
+
class_model: T = self.__class_model
|
|
527
|
+
counter: int = 0
|
|
528
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers) as executor:
|
|
529
|
+
for branch_number in branch_numbers:
|
|
530
|
+
future = executor.submit(
|
|
531
|
+
search_task_fn,
|
|
532
|
+
branch_number,
|
|
533
|
+
filter_fn,
|
|
534
|
+
hash_reduce_left,
|
|
535
|
+
db_root,
|
|
536
|
+
class_model,
|
|
537
|
+
)
|
|
538
|
+
counter += future.result(timeout)
|
|
539
|
+
if counter < 0:
|
|
540
|
+
self._sync_counter_documents(counter)
|
|
541
|
+
return abs(counter)
|
scruby/errors.py
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Scruby Exceptions."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
__all__ = (
|
|
5
|
+
__all__ = (
|
|
6
|
+
"ScrubyException",
|
|
7
|
+
"MetadataValueError",
|
|
8
|
+
)
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
class ScrubyException(Exception):
|
|
9
12
|
"""Root Custom Exception."""
|
|
10
13
|
|
|
11
|
-
def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
|
|
14
|
+
def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def] # noqa: D107
|
|
12
15
|
super().__init__(*args, **kwargs)
|
|
13
16
|
|
|
14
17
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scruby
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.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
|
|
@@ -175,7 +175,7 @@ from scruby import Scruby, constants
|
|
|
175
175
|
from pprint import pprint as pp
|
|
176
176
|
|
|
177
177
|
constants.DB_ROOT = "ScrubyDB" # By default = "ScrubyDB"
|
|
178
|
-
constants.
|
|
178
|
+
constants.HASH_REDUCE_LEFT = 6 # 256 branches in collection
|
|
179
179
|
# (main purpose is tests).
|
|
180
180
|
|
|
181
181
|
class User(BaseModel):
|
|
@@ -246,7 +246,7 @@ from scruby import Scruby, constants
|
|
|
246
246
|
from pprint import pprint as pp
|
|
247
247
|
|
|
248
248
|
constants.DB_ROOT = "ScrubyDB" # By default = "ScrubyDB"
|
|
249
|
-
constants.
|
|
249
|
+
constants.HASH_REDUCE_LEFT = 6 # 256 branches in collection
|
|
250
250
|
# (main purpose is tests).
|
|
251
251
|
|
|
252
252
|
class User(BaseModel):
|
|
@@ -274,7 +274,7 @@ async def main() -> None:
|
|
|
274
274
|
await db.set_key(f"+44798612345{num}", user)
|
|
275
275
|
|
|
276
276
|
# Find users by email.
|
|
277
|
-
users: list[User] | None = user_coll.
|
|
277
|
+
users: list[User] | None = user_coll.find_many(
|
|
278
278
|
filter_fn=lambda doc: doc.email == "John_Smith_5@gmail.com" or doc.email == "John_Smith_8@gmail.com",
|
|
279
279
|
)
|
|
280
280
|
if users is not None:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
scruby/__init__.py,sha256=wFwUS1KcLxfIopXOVS8gPue9fNzIIU2cVj_RgK5drz4,849
|
|
2
|
+
scruby/constants.py,sha256=3LZfcxcuRqwzoB0-iogLMjKBZRdxfWJmTbyPwVRhQgY,1007
|
|
3
|
+
scruby/db.py,sha256=Q7J4OKS2emiF0KzZClSjpBBLjohnccZ81T4pgoWNxqA,20269
|
|
4
|
+
scruby/errors.py,sha256=aHQri4LNcFVQrSHwjyzb1fL8O49SwjYEU4QgMOo4uyA,622
|
|
5
|
+
scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
scruby-0.11.0.dist-info/METADATA,sha256=yS9LDAYAqmxxn8cXHKbO7BmPEsX4o7th3VVFtgr9aoo,10824
|
|
7
|
+
scruby-0.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
8
|
+
scruby-0.11.0.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
|
|
9
|
+
scruby-0.11.0.dist-info/RECORD,,
|
scruby-0.10.3.dist-info/RECORD
DELETED
|
@@ -1,9 +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=J14Xjyc6iyb-cwBKiH8rJuioEHoYfNkLTezzvQBsJng,16181
|
|
4
|
-
scruby/errors.py,sha256=4G0zNVzulBE9mM2iJLdg0EXP_W8n-L6EjZrkCCErvAU,574
|
|
5
|
-
scruby/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
scruby-0.10.3.dist-info/METADATA,sha256=JGgVH8QKtA-iGifWhNdSczfuglIT2RRw5njRuNKvG3M,10829
|
|
7
|
-
scruby-0.10.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
8
|
-
scruby-0.10.3.dist-info/licenses/LICENSE,sha256=2zZINd6m_jNYlowdQImlEizyhSui5cBAJZRhWQURcEc,1095
|
|
9
|
-
scruby-0.10.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|