litedict
Dictionary implemented on top of SQLite
Why?
You can use this to implement a persistent dictionary. It also uses some SQLite syntax to enable getting keys using pattern matching (see examples).
Installation
pip install litedict
Alternatives
- RaRe-Technologies/sqlitedict: This library uses a separate writing thread. Modern versions of SQLite are thread safe by default (serialized), so a separate writing thread is not strictly needed. It can be helpful to avoid DB locks, but it also adds extra complexity. That implementation is also missing some performance optimizations that are present in this repository.
Examples
The examples are taken from the tests in tests.ipynb
from litedict import SQLDict
TEST_1 = "key_test_1"
TEST_2 = "key_test_2"
Basic functionality
d = SQLDict(":memory:")
d[TEST_1] = "asdfoobar"
assert d[TEST_1] == "asdfoobar"
del d[TEST_1]
assert d.get(TEST_1, None) is None
# execute multiple instructions inside a transaction
with d.transaction():
d["asd"] = "efg"
d["foo"] = "bar"
Glob matching
d[TEST_1] = "asdfoobar"
d[TEST_2] = "foobarasd"
d["key_testx_3"] = "barasdfoo"
assert d.glob("key_test*") == ["asdfoobar", "foobarasd", "barasdfoo"]
assert d.glob("key_test_?") == ["asdfoobar", "foobarasd"]
assert d.glob("key_tes[tx]*") == ["asdfoobar", "foobarasd", "barasdfoo"]
Numbers
d[TEST_1] = 1
d[TEST_2] = 2
assert d[TEST_1] + d[TEST_2] == 3
Benchmarks
from string import ascii_lowercase, printable
from random import choice
import random
def random_string(string_length=10, fuzz=False, space=False):
"""Generate a random string of fixed length """
letters = ascii_lowercase
letters = letters + " " if space else letters
if fuzz:
letters = printable
return "".join(choice(letters) for i in range(string_length))
import gc
import pickle
import json
Pickle
d = SQLDict(
":memory:",
encoder=lambda x: pickle.dumps(x).hex(),
decoder=lambda x: pickle.loads(bytes.fromhex(x)),
)
gc.collect()
# %%timeit -n20000 -r10
d[random_string(8)] = random_string(50)
d.get(random_string(8), None)
# 69.2 µs ± 4.84 µs per loop (mean ± std. dev. of 10 runs, 20000 loops each)
Noop
d = SQLDict(
":memory:",
encoder=lambda x: x,
decoder=lambda x: x,
)
gc.collect()
# %%timeit -n20000 -r10
d[random_string(8)] = random_string(50)
d.get(random_string(8), None)
# 66.8 µs ± 2.41 µs per loop (mean ± std. dev. of 10 runs, 20000 loops each)
JSON
d = SQLDict(
":memory:",
encoder=lambda x: json.dumps(x),
decoder=lambda x: json.loads(x),
)
gc.collect()
# %%timeit -n20000 -r10
d[random_string(8)] = random_string(50)
d.get(random_string(8), None)
# 68.6 µs ± 3.07 µs per loop (mean ± std. dev. of 10 runs, 20000 loops each)
Pickle Python obj
d = SQLDict(
":memory:",
encoder=lambda x: pickle.dumps(x).hex(),
decoder=lambda x: pickle.loads(bytes.fromhex(x)),
)
gc.collect()
class C:
def __init__(self, x):
self.x = x
def pp(self):
return x
def f(self):
def _f(y):
return y * self.x ** 2
return _f
# %%timeit -n20000 -r10
d[random_string(8)] = C(random.randint(1, 200))
d.get(random_string(8), None)
# 41.1 µs ± 2.75 µs per loop (mean ± std. dev. of 10 runs, 20000 loops each)
Dictionary
d = {}
gc.collect()
# %%timeit -n20000 -r10
d[random_string(8)] = random_string(50)
d.get(random_string(8), None)
# 53.1 µs ± 4.42 µs per loop (mean ± std. dev. of 10 runs, 20000 loops each)
Changelog
- 0.3
- Add transactions as part of the dictionary
Meta
Ricardo Ander-Egg Aguilar – @ricardoanderegg –
Distributed under the MIT license. See LICENSE for more information.
Contributing
The only hard rules for the project are:
- No extra dependencies allowed
- No extra files, everything must be inside the main module's
.pyfile. - Tests must be inside the
tests.ipynbnotebook.
Metadata
Release files for litedict 0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| litedict-0.5.tar.gz | 5.1 kB | Without provenance | Details for litedict-0.5.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| litedict-0.5-py3-none-any.whl | Python 3 | none | any | Details for litedict-0.5-py3-none-any.whl |
Total release size: 10.6 kB
Release files / litedict-0.5.tar.gz
| Download URL | litedict-0.5.tar.gz |
|---|---|
| Size | 5.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c9e4e6deba08f4a1b4c5784c27ea151fc5cdefcf8e3271c89ffabf49200f332c
|
|
BLAKE2b-256 checksum How to use checksums |
5885644341eedad5f2fcbfd5c3ad11f31c759a6aafcfd5b575b70d783349fe1e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.0 CPython/3.9.12
|
Release files / litedict-0.5-py3-none-any.whl
| Download URL | litedict-0.5-py3-none-any.whl |
|---|---|
| Size | 5.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dbb8dd65ce97601f4d0994844ea1073aebbc015f7549889fb98eaa720e5196bb
|
|
BLAKE2b-256 checksum How to use checksums |
1e409da724d7ff9ecfb3af3e3f5f59643350c07d8885e0ec82ab0566e191c7b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.0 CPython/3.9.12
|
Security for litedict 0.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.