Skip to content

Commit

Permalink
V3.2.0 pre release (#82)
Browse files Browse the repository at this point in the history
* Bumped version v3.2.0

* Add delete raise keyerror (#81)

* Added dict_compliant flag, for delete it will raise if key not set

* Changed passed the linters

* Changed docstring

* Added insertion ordering under the dict_compliant flag

* Changed passed the linters

* Changed new naming convention for tests

* Added pydocstyle as doctype check

* Changed docstring indentation issue

* Changed test naming convention

* Added testing for the dict_compliant mode

* Changed moved ordered python dict into new class

* Added new file

* Added sphinx docs for new file

* Added tests, and raised not implemented for chain commands on PythonRedisDict

* Changed updated readme
  • Loading branch information
Attumm authored Nov 23, 2024
1 parent 261bc74 commit 01b148c
Show file tree
Hide file tree
Showing 23 changed files with 1,478 additions and 429 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ jobs:
run: |
python -m pylama -i E501,E231 src
- name: Run mypy strict
- name: Run type check with mypy strict
run: |
mypy
- name: Doctype Check
- name: Run Doctype Check
run: |
darglint src/redis_dict/
pydocstyle src/redis_dict/
- name: Run Security check
run: |
Expand All @@ -62,7 +63,7 @@ jobs:
env:
PYTHONPATH: src
run: |
coverage run -m unittest discover -p "*tests.py"
coverage run -m unittest discover -s tests
- name: Upload coverage reports to Codecov, send only once
if: matrix.python-version == '3.12'
Expand Down
104 changes: 58 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,48 @@ In Redis our example looks like this.
"str:hello world"
```

## Types

### standard types
RedisDict supports a range of Python data types, from basic types to nested structures.
Basic types are handled natively, while complex data types like lists and dictionaries, RedisDict uses JSON serialization, specifically avoiding [pickle](https://docs.python.org/3/library/pickle.html) due to its security vulnerabilities within distributed computing contexts.
Although the library supports nested structures, the recommended best practice is to use RedisDict as a shallow dictionary.
This approach optimizes Redis database performance and efficiency by ensuring that each set and get operation efficiently maps to Redis's key-value storage capabilities, while still preserving the library's Pythonic interface.
Following types are supported:
`str, int, float, bool, NoneType, list, dict, tuple, set, datetime, date, time, timedelta, Decimal, complex, bytes, UUID, OrderedDict, defaultdict, frozenset`
```python
from uuid import UUID
from decimal import Decimal
from collections import OrderedDict, defaultdict
from datetime import datetime, date, time, timedelta

dic = RedisDict()

dic["string"] = "Hello World"
dic["number"] = 42
dic["float"] = 3.14
dic["bool"] = True
dic["None"] = None

dic["list"] = [1, 2, 3]
dic["dict"] = {"a": 1, "b": 2}
dic["tuple"] = (1, 2, 3)
dic["set"] = {1, 2, 3}

dic["datetime"] = datetime.date(2024, 1, 1, 12, 30, 45)
dic["date"] = date(2024, 1, 1)
dic["time"] = time(12, 30, 45)
dic["delta"] = timedelta(days=1, hours=2)

dic["decimal"] = Decimal("3.14159")
dic["complex"] = complex(1, 2)
dic["bytes"] = bytes([72, 101, 108, 108, 111])
dic["uuid"] = UUID('12345678-1234-5678-1234-567812345678')

dic["ordered"] = OrderedDict([('a', 1), ('b', 2)])
dic["default"] = defaultdict(int, {'a': 1, 'b': 2})
dic["frozen"] = frozenset([1, 2, 3])
```

### Namespaces
Acting as an identifier for your dictionary across different systems, RedisDict employs namespaces for organized data management. When a namespace isn't specified, "main" becomes the default. Thus allowing for data organization across systems and projects with the same redis instance.
Expand Down Expand Up @@ -218,51 +260,6 @@ print(dic["d"]) # Output: 4
For more advanced examples of RedisDict, please refer to the unit-test files in the repository. All features and functionalities are thoroughly tested in [unit tests (here)](https://github.com/Attumm/redis-dict/blob/main/tests/unit/tests.py#L1) Or take a look at load test for batching [load test](https://github.com/Attumm/redis-dict/blob/main/tests/load/load_test.py#L1).
The unit-tests can be as used as a starting point.

## Types

### standard types
RedisDict supports a range of Python data types, from basic types to nested structures.
Basic types are handled natively, while complex data types like lists and dictionaries, RedisDict uses JSON serialization, specifically avoiding `pickle` due to its [security vulnerabilities](https://docs.python.org/3/library/pickle.html) in distributed computing contexts.
Although the library supports nested structures, the recommended best practice is to use RedisDict as a shallow dictionary.
This approach optimizes Redis database performance and efficiency by ensuring that each set and get operation efficiently maps to Redis's key-value storage capabilities, while still preserving the library's Pythonic interface.
Following types are supported:
`str, int, float, bool, NoneType, list, dict, tuple, set, datetime, date, time, timedelta, Decimal, complex, bytes, UUID, OrderedDict, defaultdict, frozenset`
```python
from uuid import UUID
from decimal import Decimal
from collections import OrderedDict, defaultdict
from datetime import datetime, date, time, timedelta

dic = RedisDict()

dic["string"] = "Hello World"
dic["number"] = 42
dic["float"] = 3.14
dic["bool"] = True
dic["None"] = None

dic["list"] = [1, 2, 3]
dic["dict"] = {"a": 1, "b": 2}
dic["tuple"] = (1, 2, 3)
dic["set"] = {1, 2, 3}

dic["datetime"] = datetime.date(2024, 1, 1, 12, 30, 45)
dic["date"] = date(2024, 1, 1)
dic["time"] = time(12, 30, 45)
dic["delta"] = timedelta(days=1, hours=2)

dic["decimal"] = Decimal("3.14159")
dic["complex"] = complex(1, 2)
dic["bytes"] = bytes([72, 101, 108, 108, 111])
dic["uuid"] = UUID('12345678-1234-5678-1234-567812345678')

dic["ordered"] = OrderedDict([('a', 1), ('b', 2)])
dic["default"] = defaultdict(int, {'a': 1, 'b': 2})
dic["frozen"] = frozenset([1, 2, 3])
```



### Nested types
Nested Types
RedisDict supports nested structures with mixed types through JSON serialization. The feature works by utilizing JSON encoding and decoding under the hood. While this represents an upgrade in functionality, the feature is not fully implemented and should be used with caution. For optimal performance, using shallow dictionaries is recommended.
Expand Down Expand Up @@ -322,6 +319,21 @@ assert result.name == person.name
assert result.age == person.age
```

### Insertion Order
For insertion order, use the PythonRedisDict. This class is focused on Python dictionary behavior one-to-one.
It will eventually become a drop-in replacement for dictionary. Currently, nested types and typed keys are not yet supported but will be added in the future.

```python
from redis_dict import PythonRedisDict

dic = PythonRedisDict()
dic["1"] = "one"
dic["2"] = "two"
dic["3"] = "three"

assert list(dic.keys()) == ["1", "2", "3"]
```

For more information on [extending types](https://github.com/Attumm/redis-dict/blob/main/tests/unit/extend_types_tests.py).
### Redis Encryption
Setup guide for configuring and utilizing encrypted Redis TLS for redis-dict.
Expand All @@ -345,7 +357,7 @@ redis_config = {
'port': 6380,
}

confid_dic = RedisDict(**redis_config)
config_dic = RedisDict(**redis_config)
```

## Installation
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "redis-dict"
version = "3.1.2"
version = "3.2.0"
description = "Dictionary with Redis as storage backend"
authors = [
{name = "Melvin Bijman", email = "[email protected]"},
Expand Down
11 changes: 11 additions & 0 deletions scripts/build_dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
set -e

rm -rf .venv_dev
python3 -m venv .venv_dev
source .venv_dev/bin/activate

pip install --upgrade pip
pip install -e ".[dev]"

deactivate
12 changes: 12 additions & 0 deletions scripts/generate_sphinx_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def setup(app):
:maxdepth: 2
redis_dict/core
redis_dict/python_dict
redis_dict/type_management
"""

Expand Down Expand Up @@ -147,7 +148,15 @@ def setup(app):
:show-inheritance:
:noindex:
"""
python_redis_dict = """Python Redis Dict
==============================
.. automodule:: redis_dict.python_dict
:members:
:undoc-members:
:show-inheritance:
:noindex:
"""

makefile_content = """
# Minimal makefile for Sphinx documentation
Expand Down Expand Up @@ -183,5 +192,8 @@ def setup(app):
with open(module_docs_path / 'type_management.rst', 'w') as f:
f.write(type_management)

with open(module_docs_path / 'python_dict.rst', 'w') as f:
f.write(python_redis_dict)

if __name__ == '__main__':
generate_configs()
32 changes: 32 additions & 0 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
set -e

#!/bin/bash
set -e

if [ ! -d ".venv_dev" ]; then
echo "Virtual environment not found. Running build script..."
./scripts/build_dev.sh
fi

source .venv_dev/bin/activate

# Type Check
python -m mypy

# Doctype Check
darglint src/redis_dict/

# Multiple linters
python -m pylama -i E501,E231 src

# Security Check
bandit -r src/redis_dict

# Docstring Check
pydocstyle src/redis_dict/

# Pylint
pylint src/

deactivate
10 changes: 5 additions & 5 deletions scripts/tests.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/bin/bash
set -e

python3 -m venv .venv_dev
source .venv_dev/bin/activate
if [ ! -d ".venv_dev" ]; then
echo "Virtual environment not found. Running build script..."
./scripts/build_dev.sh
fi

python -m unittest discover -s tests

deactivate
.venv_dev/bin/python -m unittest discover -s tests --failfast -v
9 changes: 6 additions & 3 deletions scripts/verify.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#!/bin/bash
set -e

rm -rf .venv_dev
python3 -m venv .venv_dev
if [ ! -d ".venv_dev" ]; then
echo "Virtual environment not found. Running build script..."
./scripts/build_dev.sh
fi

source .venv_dev/bin/activate

# Type Check
Expand All @@ -21,6 +24,6 @@ python -m unittest discover -s tests
bandit -r src/redis_dict

# Docstring Check
# pydocstyle src/redis_dict/
pydocstyle src/redis_dict/

deactivate
2 changes: 2 additions & 0 deletions src/redis_dict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from importlib.metadata import version, PackageNotFoundError

from .core import RedisDict
from .python_dict import PythonRedisDict
from .type_management import decoding_registry, encoding_registry, RedisDictJSONEncoder, RedisDictJSONDecoder

__all__ = [
'RedisDict',
'PythonRedisDict',
'decoding_registry',
'encoding_registry',
'RedisDictJSONEncoder',
Expand Down
Loading

0 comments on commit 01b148c

Please sign in to comment.