From 1b2ebcfb99e819b83b5c0997834883294e4959bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Rafael=20Siqueira?= Date: Fri, 11 Apr 2025 21:28:02 -0300 Subject: [PATCH] update --- http-api/cli/seeds.py | 1 + layercake/layercake/dynamodb.py | 130 ++++++++++++++++++------------- layercake/mkdocs.yml | 7 +- layercake/pyproject.toml | 3 +- layercake/tests/test_dynamodb.py | 4 +- layercake/uv.lock | 24 +++++- 6 files changed, 107 insertions(+), 62 deletions(-) diff --git a/http-api/cli/seeds.py b/http-api/cli/seeds.py index 1b6e0a0..4bdbc16 100644 --- a/http-api/cli/seeds.py +++ b/http-api/cli/seeds.py @@ -92,6 +92,7 @@ if __name__ == '__main__': for file in tqdm(jsonl_files, desc='Processing files'): with jsonlines.open(f'seeds/{file}') as lines: table_name = file.removesuffix('.jsonl') + reader = jsonlines.Reader(fp) for line in tqdm(lines, desc=f'Processing lines in {file}'): put_item(line, table_name, dynamodb_client) diff --git a/layercake/layercake/dynamodb.py b/layercake/layercake/dynamodb.py index a806ef5..50caa81 100644 --- a/layercake/layercake/dynamodb.py +++ b/layercake/layercake/dynamodb.py @@ -12,6 +12,7 @@ from uuid import UUID from aws_lambda_powertools import Logger from boto3.dynamodb.types import TypeDeserializer, TypeSerializer from botocore.exceptions import ClientError +from glom import glom from .dateutils import now, timestamp from .funcs import omit @@ -58,21 +59,20 @@ if TYPE_CHECKING: @dataclass class ComposeKey(str): - """Creates a composite key by joining string parts with a specified delimiter. - If a prefix is provided, it is added at the beginning of the key parts. - - Example - ------- - >>> ComposeKey(('abc', 'xyz'), prefix='examples', delimiter='#') - 'examples#abc#xyz' - """ - keyparts: str | tuple[str, ...] prefix: str | None = None delimiter: str = '#' else: class ComposeKey(str): + """Creates a composite key by joining string parts with a specified delimiter. + If a prefix is provided, it is added at the beginning of the key parts. + + Example + ------- + ComposeKey(('abc', 'xyz'), prefix='examples', delimiter='#') + """ + def __new__( cls, keyparts: str | tuple[str, ...], @@ -131,17 +131,31 @@ if TYPE_CHECKING: class SortKey(str): sk: str table_name: str | None = None + path_spec: str | None = None else: class SortKey(str): - def __new__(cls, sk: str, *, table_name: str | None = None) -> str: + def __new__( + cls, + sk: str, + *, + table_name: str | None = None, + path_spec: str | None = None, + ) -> str: return super().__new__(cls, sk) - def __init__(self, sk: str, *, table_name: str | None = None) -> None: + def __init__( + self, + sk: str, + *, + table_name: str | None = None, + path_spec: str | None = None, + ) -> None: # __init__ is used to store the parameters for later reference. # For immutable types like str, __init__ cannot change the instance's value. self.sk = sk self.table_name = table_name + self.path_spec = path_spec @dataclass @@ -149,9 +163,9 @@ class TransactKey: """ Example ------- - >>> TransactKey('e9bb7dc6-c7b2-4d34-8931-d298353758ec') - ... + SortKey('0') - ... + SortKey('tenant') + TransactKey('e9bb7dc6-c7b2-4d34-8931-d298353758ec') + + SortKey('0') + + SortKey('tenant') """ pk: str @@ -597,18 +611,18 @@ class DynamoDBCollection: Parameters ---------- - key : Key + key: Key Key of the item to be retrieved. - path_spec : str, optional - A path specification for nested data extraction, default is None. - raise_on_error : bool, optional - If True, raises an exception when the item is not found, default is True. - exception_cls : Type[Exception], optional - Exception class to be used if the item is not found, default is MissingError. - default : Any, optional - Default value returned if the item is not found, default is None. - delimiter : str, optional - Delimiter used in key composition, default is '#'. + path_spec: str, optional + A path specification for nested data extraction. + raise_on_error: bool, optional + If True, raises an exception when the item is not found. + exception_cls: Type[Exception], optional + Exception class to be used if the item is not found. + default: Any, optional + Default value returned if the item is not found. + delimiter: str, optional + Delimiter used in key composition. Returns ------- @@ -644,10 +658,10 @@ class DynamoDBCollection: Parameters ---------- - key : Key + key: Key Key for the item to be inserted or updated. - ttl : int or datetime, optional - Time-to-live for the item, specified as a timestamp integer or datetime object, default is None. + ttl: int or datetime, optional + Time-to-live for the item, specified as a timestamp integer or datetime object. **kwargs Additional data to be stored with the item. @@ -688,14 +702,14 @@ class DynamoDBCollection: Parameters ---------- - key : Key + key: Key Key of the item to be deleted. - cond_expr : str, optional - Conditional expression for deletion, default is None. - expr_attr_names : dict, optional - Mapping of attribute names for the expression, default is None. - expr_attr_values : dict, optional - Mapping of attribute values for the expression, default is None. + cond_expr: str, optional + Conditional expression for deletion. + expr_attr_names: dict, optional + Mapping of attribute names for the expression. + expr_attr_values: dict, optional + Mapping of attribute values for the expression. Returns ------- @@ -720,21 +734,23 @@ class DynamoDBCollection: ------- **Get items using chained sort keys** - key = TransactKey('b3511b5a-cb32-4833-a373-f8223f2088d4') + SortKey('sk-1') + SortKey('sk-2') + key = ( + TransactKey('b3511b5a-cb32-4833-a373-f8223f2088d4') + + SortKey('sk-1') + SortKey('sk-2') + ) collect = DynamoDBCollection(...) items = collect.get_items(key) Parameters ---------- - key : TransactKey + key: TransactKey A TransactKey instance that contains a partition key and one or more sort keys. If no sort key is provided, the transaction is skipped. - flatten_top : bool, optional + flatten_top: bool, optional Determines whether the first nested item in the transaction result should be flattened, i.e., extracted to serve as the primary item at the top level of the returned dict. If True, the nested item is promoted to the top level. - The default is True. Returns ------- @@ -764,9 +780,11 @@ class DynamoDBCollection: else: head, tail = {}, items - return head | { - k: omit((PK, SK), item) for k, item in zip(sortkeys, tail) if item - } + def _getin(sk: SortKey, v: dict) -> dict: + v = omit((PK, SK), v) + return glom(v, sk.path_spec) if sk.path_spec else v + + return head | {k: _getin(k, item) for k, item in zip(sortkeys, tail) if item} def query( self, @@ -801,20 +819,20 @@ class DynamoDBCollection: Parameters ---------- - key : PartitionKey or KeyPair + key: PartitionKey or KeyPair Partition key or Key pair used for the query. - expr_attr_name : dict, optional - Additional mapping for attribute names, default is {}. - expr_attr_values : dict, optional - Additional mapping for attribute values, default is {}. - start_key : str, optional - Starting key for pagination, default is None. - filter_expr : str, optional - Filter expression for the query, default is None. - index_forward : bool, optional - Order of the results; True for ascending order, default is False. - limit : int, optional - Maximum number of items to return, default is LIMIT. + expr_attr_name: dict, optional + Additional mapping for attribute names. + expr_attr_values: dict, optional + Additional mapping for attribute values. + start_key: str, optional + Starting key for pagination. + filter_expr: str, optional + Filter expression for the query. + index_forward: bool, optional + Order of the results; True for ascending order. + limit: int, optional + Maximum number of items to return. Returns ------- @@ -823,7 +841,7 @@ class DynamoDBCollection: See Also -------- - DynamoDB.Client.query : https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/query.html + DynamoDB.Client.query: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/query.html """ key_cond_expr = ( '#pk = :pk AND begins_with(#sk, :sk)' diff --git a/layercake/mkdocs.yml b/layercake/mkdocs.yml index a5b098e..3f6f699 100644 --- a/layercake/mkdocs.yml +++ b/layercake/mkdocs.yml @@ -4,8 +4,11 @@ theme: name: "readthedocs" plugins: - - mkdocstrings - + - mkdocstrings: + handlers: + python: + options: + docstring_style: numpy nav: - index.md - API reference: reference.md diff --git a/layercake/pyproject.toml b/layercake/pyproject.toml index 862392b..64a8284 100644 --- a/layercake/pyproject.toml +++ b/layercake/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "layercake" -version = "0.2.1" +version = "0.2.5" description = "Packages shared dependencies to optimize deployment and ensure consistency across functions." readme = "README.md" authors = [ @@ -23,6 +23,7 @@ dependencies = [ "meilisearch>=0.34.0", "arnparse>=0.0.2", "weasyprint>=65.0", + "uuid-utils>=0.10.0", ] [dependency-groups] diff --git a/layercake/tests/test_dynamodb.py b/layercake/tests/test_dynamodb.py index f986c8e..1bfa6cb 100644 --- a/layercake/tests/test_dynamodb.py +++ b/layercake/tests/test_dynamodb.py @@ -249,7 +249,7 @@ def test_collection_get_items( doc = collect.get_items( TransactKey('cJtK9SsnJhKPyxESe7g3DG') + SortKey('0') - + SortKey('billing_policy') + + SortKey('billing_policy', path_spec='payment_method') + SortKey('payment_policy'), ) @@ -259,7 +259,7 @@ def test_collection_get_items( 'id': 'cJtK9SsnJhKPyxESe7g3DG', 'cnpj': '15608435000190', 'email': 'org+15608435000190@users.noreply.betaeducacao.com.br', - 'billing_policy': {'billing_day': Decimal('1'), 'payment_method': 'PIX'}, + 'billing_policy': 'PIX', 'payment_policy': {'due_days': Decimal('90')}, } diff --git a/layercake/uv.lock b/layercake/uv.lock index 8c3e18f..e685946 100644 --- a/layercake/uv.lock +++ b/layercake/uv.lock @@ -600,7 +600,7 @@ wheels = [ [[package]] name = "layercake" -version = "0.2.0" +version = "0.2.4" source = { editable = "." } dependencies = [ { name = "arnparse" }, @@ -617,6 +617,7 @@ dependencies = [ { name = "pydantic-extra-types" }, { name = "pytz" }, { name = "requests" }, + { name = "uuid-utils" }, { name = "weasyprint" }, ] @@ -646,6 +647,7 @@ requires-dist = [ { name = "pydantic-extra-types", specifier = ">=2.10.3" }, { name = "pytz", specifier = ">=2025.1" }, { name = "requests", specifier = ">=2.32.3" }, + { name = "uuid-utils", specifier = ">=0.10.0" }, { name = "weasyprint", specifier = ">=65.0" }, ] @@ -1277,6 +1279,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, ] +[[package]] +name = "uuid-utils" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/0a/cbdb2eb4845dafeb632d02a18f47b02f87f2ce4f25266f5e3c017976ce89/uuid_utils-0.10.0.tar.gz", hash = "sha256:5db0e1890e8f008657ffe6ded4d9459af724ab114cfe82af1557c87545301539", size = 18828 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/54/9d22fa16b19e5d1676eba510f08a9c458d96e2a62ff2c8ebad64251afb18/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d5a4508feefec62456cd6a41bcdde458d56827d908f226803b886d22a3d5e63", size = 573006 }, + { url = "https://files.pythonhosted.org/packages/08/8e/f895c6e52aa603e521fbc13b8626ba5dd99b6e2f5a55aa96ba5b232f4c53/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dbefc2b9113f9dfe56bdae58301a2b3c53792221410d422826f3d1e3e6555fe7", size = 292543 }, + { url = "https://files.pythonhosted.org/packages/b6/58/cc4834f377a5e97d6e184408ad96d13042308de56643b6e24afe1f6f34df/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffc49c33edf87d1ec8112a9b43e4cf55326877716f929c165a2cc307d31c73d5", size = 323340 }, + { url = "https://files.pythonhosted.org/packages/37/e3/6aeddf148f6a7dd7759621b000e8c85382ec83f52ae79b60842d1dc3ab6b/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0636b6208f69d5a4e629707ad2a89a04dfa8d1023e1999181f6830646ca048a1", size = 329653 }, + { url = "https://files.pythonhosted.org/packages/0c/00/dd6c2164ace70b7b1671d9129267df331481d7d1e5f9c5e6a564f07953f6/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc06452856b724df9dedfc161c3582199547da54aeb81915ec2ed54f92d19b0", size = 365471 }, + { url = "https://files.pythonhosted.org/packages/b4/e7/0ab8080fcae5462a7b5e555c1cef3d63457baffb97a59b9bc7b005a3ecb1/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:263b2589111c61decdd74a762e8f850c9e4386fb78d2cf7cb4dfc537054cda1b", size = 325844 }, + { url = "https://files.pythonhosted.org/packages/73/39/52d94e9ef75b03f44b39ffc6ac3167e93e74ef4d010a93d25589d9f48540/uuid_utils-0.10.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a558db48b7096de6b4d2d2210d82bba8586a6d55f99106b03bb7d01dc5c5bcd6", size = 344389 }, + { url = "https://files.pythonhosted.org/packages/7c/29/4824566f62666238290d99c62a58e4ab2a8b9cf2eccf94cebd9b3359131e/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:807465067f3c892514230326ac71a79b28a8dfe2c88ecd2d5675fc844f3c76b5", size = 510078 }, + { url = "https://files.pythonhosted.org/packages/5e/8f/bbcc7130d652462c685f0d3bd26bb214b754215b476340885a4cb50fb89a/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:57423d4a2b9d7b916de6dbd75ba85465a28f9578a89a97f7d3e098d9aa4e5d4a", size = 515937 }, + { url = "https://files.pythonhosted.org/packages/23/f8/34e0c00f5f188604d336713e6a020fcf53b10998e8ab24735a39ab076740/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:76d8d660f18ff6b767e319b1b5f927350cd92eafa4831d7ef5b57fdd1d91f974", size = 494111 }, + { url = "https://files.pythonhosted.org/packages/1a/52/b7f0066cc90a7a9c28d54061ed195cd617fde822e5d6ac3ccc88509c3c44/uuid_utils-0.10.0-cp39-abi3-win32.whl", hash = "sha256:6c11a71489338837db0b902b75e1ba7618d5d29f05fde4f68b3f909177dbc226", size = 173520 }, + { url = "https://files.pythonhosted.org/packages/8b/15/f04f58094674d333974243fb45d2c740cf4b79186fb707168e57943c84a3/uuid_utils-0.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:11c55ae64f6c0a7a0c741deae8ca2a4eaa11e9c09dbb7bec2099635696034cf7", size = 182965 }, +] + [[package]] name = "watchdog" version = "6.0.0"