Dynamizer
A supportive set of defaults for dynamodb. Dynamizer doesn't aim to abstract away the nuances of dynamodb, but rather to provide effective defaults for the repetitive tasks of (de)serializing models to and from dynamodb.
It provides:
- Automatic deserialization from dynamo's format. This is helpful when processing a change stream from dynamo.
- Overwrite detection. If a model is changed between reading it and writing it back to dynamodb an error will be raised, preventing the unintentional overwriting of existing data.
- Supportive base delete, save, and load function to make a programmers life easier.
Usage
Dynamizer models are built on top of immutable data classes.
import dataclasses
import dynamizer
@dataclasses.dataclass(frozen=True)
class DemoClass(dynamizer.DynamiteModel):
"""A demo class."""
foobar: str
fizbuzz: typing.Optional[str] = None
@property
def hash_key(self) -> str:
"""
Get the hash key.
Dynamizer can't tell you what the right hash/range key scheme is
write for your use case and access patterns so you must define
how to translate the model's data into a hash and range key.
"""
return f"hash-key/{self.foobar}"
@property
def range_key(self) -> str:
"""Get the range key."""
return "/range-key"
def _gs1(self) -> str:
"""
Get the gs1 value.
Dynamizer will also support you in instantiating any global secondary
indices. It expects these to be defined matching the pattern
`^_?gs\d+$`. Dynamizer searches the class for any functions matching
this pattern and automatically manages their lifecycle within dynamodb,
creating them dynamically as the model is saved, and deleting them
if they are null in some part of the models life. Note that The index
itself still needs to be created within dynamodb.
"""
return f"{self.foobar}/hash-key"
@classmethod
def load(cls, my_identifier: typing.Any) -> "DemoClass":
"""
Load a model from dynamodb.
Dynamizer does not provide a default load function, since it doesn't
know all of your specific access patterns and how incoming arguments
are to be translated into a hash key, range key pair, but it does
provide helpful secondary methods to make writing a load function
easier.
"""
hash_key = _hash_key(my_identifier)
range_key = _hash_key(my_identifier)
client = boto3.client("dynamodb")
result = cls._base_load(client, "my-table-name", hash_key, range_key)
if result is None:
raise NotFoundError(f"Could not find {my_identifier}")
return result
@classmethod
def list_group(cls, my_group: typing.Any) -> typing.List["DemoClass"]:
"""
List a model under the specified group.
Dynamizer provides methods for easily converting a dynamodb response
into a python model making it easier to write functions defining a
variety of access patterns.
"""
...
response = client.query("Something fancy")
return [cls.inflate(item) for item in response.get("Items", [])]
def save(self) -> "DemoClass":
"""
Save a model.
Dynamizer keeps a count of changes to a model and checks when saving
to ensure that no changes have come in since the model was initially
read. This prevents data from being overwritten both during initial
creation and during updates.
"""
...
return self._base_save(client, "table_to_save_to")
def delete(self):
"""
Delete a model.
Like during saves, Dynamizer keeps a count of changes and will prevent
a delete from taking place if an update has taken place since the last
read.
"""
...
self._base_delete(client, "table_to_delete_from")
Mocking
Dynamizer provides a mechanism for mocking out dynamodb calls for testing. The initial state of dynamodb can be set via yaml files.
import dynamizer.mock
data = yaml.safe_load("/path/to/data.yaml")
with dynamizer.mock.from_yaml(data):
# Within this context dynamodb will have the state defined in data.yaml
The expected format of the yaml file is:
- table_name: my-table-name
region: us-east-1 # Optional
secondary_indexes: # Optional
- name: gs1-gs2
hash_key: gs1
range_key: gs2
objects:
MyDynamizerSubCls:
- foo: {S: bar}
fiz: {S: buzz}
AnotherDynamizerSubCls:
- mock: {S: data}
Metadata
Release files for dynamizer 0.2.14
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 |
|---|---|---|---|---|
| dynamizer-0.2.14.tar.gz | 8.0 kB | Without provenance | Details for dynamizer-0.2.14.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| dynamizer-0.2.14-py3-none-any.whl | Python 3 | none | any | Details for dynamizer-0.2.14-py3-none-any.whl |
Total release size: 17.8 kB
Release files / dynamizer-0.2.14.tar.gz
| Download URL | dynamizer-0.2.14.tar.gz |
|---|---|
| Size | 8.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5e96267dbfac6e16950d33dec29dc9e80042ea4dcaeccb93adafc393bf337e94
|
|
BLAKE2b-256 checksum How to use checksums |
6d1429d154ca8db4d9dcdf347a1720a8d7b8b1fdf80d1803c8f16de9be9c9516
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.2 CPython/3.13.3 Linux/6.14.4-300.fc42.x86_64
|
Release files / dynamizer-0.2.14-py3-none-any.whl
| Download URL | dynamizer-0.2.14-py3-none-any.whl |
|---|---|
| Size | 9.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
38d787359c44d3e78e0fa49d86bd82e95db7159db806e3a9ce266ce0bdd113fd
|
|
BLAKE2b-256 checksum How to use checksums |
49b212b27f3abd4238de6dfe3b506493bc76e8b58a28ab0c41af11b53e70cda0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.2 CPython/3.13.3 Linux/6.14.4-300.fc42.x86_64
|
Security for dynamizer 0.2.14
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.