From cd5783b9f01200df7db29be2ad7127cb75511957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?c=C4=83t=C4=83lin?= Date: Sat, 9 Dec 2023 11:29:28 +0100 Subject: [PATCH] chore: add mypy --- .pre-commit-config.yaml | 10 ++- Dockerfile | 4 +- apps/http/litestar/app.py | 15 ++-- pdm.lock | 144 +++++++++++++++++++++++--------------- pyproject.toml | 18 +++-- secretsanta/domain.py | 5 +- secretsanta/repo.py | 3 +- secretsanta/service.py | 11 ++- 8 files changed, 128 insertions(+), 82 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c356a2..a35748b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,4 +25,12 @@ repos: args: - --fix - --exit-non-zero-on-fix - - id: ruff-format \ No newline at end of file + - id: ruff-format + + - repo: local + hooks: + - id: mypy + name: mypy + entry: pdm run mypy + language: system + types: [ python ] \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ad9b920..f9f6018 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,8 +5,8 @@ ENV USERNAME "secretsanta" ENV APP_HOME "/home/$USERNAME" ENV APP_PATH "$APP_HOME/src" -ARG uid=1000 -ARG gid=1000 +ARG uid=10000 +ARG gid=10000 # hadolint ignore=DL3001,DL3008 RUN apt-get -y update \ diff --git a/apps/http/litestar/app.py b/apps/http/litestar/app.py index af06068..8a1d8ab 100644 --- a/apps/http/litestar/app.py +++ b/apps/http/litestar/app.py @@ -1,7 +1,7 @@ from dataclasses import asdict, dataclass from typing import Annotated, Literal -from litestar import Controller, Litestar, MediaType, Request, Response, get, put +from litestar import Controller, Litestar, MediaType, Response, get, put from litestar.params import Parameter from pydantic import UUID4 @@ -35,26 +35,19 @@ class GroupController(Controller): self.create_group_service = CreateGroupService(self.repo) self.get_pair_service = GetPairService(self.repo) - @staticmethod - def _group2urls(participants: list[str], url: str) -> list[str]: - return [f"{url}/pair/{participant_name}" for participant_name in participants] - @get("/{group_uuid:uuid}") - async def get_participants(self, request: Request, group_uuid: UUID4) -> list[str]: - participants = await self.get_participants_service.run(group_uuid) - return self._group2urls(participants, request.url) + async def get_participants(self, group_uuid: UUID4) -> list[str]: + return await self.get_participants_service.run(group_uuid) @put("/{group_uuid:uuid}") async def create_group( self, - request: Request, group_uuid: UUID4, data: CreateGroup, ) -> list[str]: - group = await self.create_group_service.run( + return await self.create_group_service.run( Group(uuid=group_uuid, **asdict(data)), ) - return self._group2urls(group.participants, request.url) @get("/{group_uuid:uuid}/pair/{participant_name:str}") async def get_pair( diff --git a/pdm.lock b/pdm.lock index 09934ad..7ecdda7 100644 --- a/pdm.lock +++ b/pdm.lock @@ -2,53 +2,53 @@ # It is not intended for manual editing. [metadata] -groups = ["default", "litestar", "testing", "dev", "linting", "chalice", "sls"] +groups = ["default", "litestar", "testing", "linting", "chalice", "sls"] strategy = ["cross_platform"] lock_version = "4.4" -content_hash = "sha256:ba9863870aa9f5f47435713bc9ae20992b801a13bced3f58aad28f2a5685614d" +content_hash = "sha256:50c4af85a208a58b532c1a92815e06aff9623ea01a5097dccf41d4c86170187f" [[package]] name = "aioboto3" -version = "12.0.0" +version = "12.1.0" requires_python = ">=3.8,<4.0" summary = "Async boto3 wrapper" dependencies = [ - "aiobotocore[boto3]==2.7.0", + "aiobotocore[boto3]==2.8.0", ] files = [ - {file = "aioboto3-12.0.0-py3-none-any.whl", hash = "sha256:23895e734f83e34827a38d3a08ccc3f4178cc8d4e3a7b7031a0cbf8efc875555"}, - {file = "aioboto3-12.0.0.tar.gz", hash = "sha256:c2bbb990b4efd2e474a1e8a42a80291faf6434b2dc8678f163208d338b2dba39"}, + {file = "aioboto3-12.1.0-py3-none-any.whl", hash = "sha256:9f9e07261ddf3d6fec04dd8d5f5a55e0cb3250089f4282f7a60054495ad9699b"}, + {file = "aioboto3-12.1.0.tar.gz", hash = "sha256:8eae15dd52c9a43845448508ad0f912028a0a176bbd85b78e1377bb5f2a4d450"}, ] [[package]] name = "aiobotocore" -version = "2.7.0" +version = "2.8.0" requires_python = ">=3.8" summary = "Async client for aws services using botocore and aiohttp" dependencies = [ "aiohttp<4.0.0,>=3.7.4.post0", "aioitertools<1.0.0,>=0.5.1", - "botocore<1.31.65,>=1.31.16", + "botocore<1.33.2,>=1.32.4", "wrapt<2.0.0,>=1.10.10", ] files = [ - {file = "aiobotocore-2.7.0-py3-none-any.whl", hash = "sha256:aec605df77ce4635a0479b50fd849aa6b640900f7b295021ecca192e1140e551"}, - {file = "aiobotocore-2.7.0.tar.gz", hash = "sha256:506591374cc0aee1bdf0ebe290560424a24af176dfe2ea7057fe1df97c4f0467"}, + {file = "aiobotocore-2.8.0-py3-none-any.whl", hash = "sha256:32e632fea387acd45416c2bbc03828ee2c2a66a7dc4bd3a9bcb808dea249c469"}, + {file = "aiobotocore-2.8.0.tar.gz", hash = "sha256:f160497cef21cfffc1a8d4219eeb27bb7b243389c2d021a812b9c0e3fb8e2bd1"}, ] [[package]] name = "aiobotocore" -version = "2.7.0" +version = "2.8.0" extras = ["boto3"] requires_python = ">=3.8" summary = "Async client for aws services using botocore and aiohttp" dependencies = [ - "aiobotocore==2.7.0", - "boto3<1.28.65,>=1.28.16", + "aiobotocore==2.8.0", + "boto3<1.33.2,>=1.29.4", ] files = [ - {file = "aiobotocore-2.7.0-py3-none-any.whl", hash = "sha256:aec605df77ce4635a0479b50fd849aa6b640900f7b295021ecca192e1140e551"}, - {file = "aiobotocore-2.7.0.tar.gz", hash = "sha256:506591374cc0aee1bdf0ebe290560424a24af176dfe2ea7057fe1df97c4f0467"}, + {file = "aiobotocore-2.8.0-py3-none-any.whl", hash = "sha256:32e632fea387acd45416c2bbc03828ee2c2a66a7dc4bd3a9bcb808dea249c469"}, + {file = "aiobotocore-2.8.0.tar.gz", hash = "sha256:f160497cef21cfffc1a8d4219eeb27bb7b243389c2d021a812b9c0e3fb8e2bd1"}, ] [[package]] @@ -180,52 +180,52 @@ files = [ [[package]] name = "boto3" -version = "1.28.64" +version = "1.33.1" requires_python = ">= 3.7" summary = "The AWS SDK for Python" dependencies = [ - "botocore<1.32.0,>=1.31.64", + "botocore<1.34.0,>=1.33.1", "jmespath<2.0.0,>=0.7.1", - "s3transfer<0.8.0,>=0.7.0", + "s3transfer<0.9.0,>=0.8.0", ] files = [ - {file = "boto3-1.28.64-py3-none-any.whl", hash = "sha256:a99150a30c038c73e89662836820a8cce914afab5ea377942a37c484b85f4438"}, - {file = "boto3-1.28.64.tar.gz", hash = "sha256:a5cf93b202568e9d378afdc84be55a6dedf11d30156289fe829e23e6d7dccabb"}, + {file = "boto3-1.33.1-py3-none-any.whl", hash = "sha256:fa5aa92d16763cb906fb4a83d6eba887342202a980bea07862af5ba40827aa5a"}, + {file = "boto3-1.33.1.tar.gz", hash = "sha256:1fe5fa75ff0f0c29a6f55e818d149d33571731e692a7b785ded7a28ac832cae8"}, ] [[package]] name = "boto3-stubs" -version = "1.33.10" +version = "1.33.11" requires_python = ">=3.7" -summary = "Type annotations for boto3 1.33.10 generated with mypy-boto3-builder 7.21.0" +summary = "Type annotations for boto3 1.33.11 generated with mypy-boto3-builder 7.21.0" dependencies = [ "botocore-stubs", "types-s3transfer", "typing-extensions>=4.1.0; python_version < \"3.12\"", ] files = [ - {file = "boto3-stubs-1.33.10.tar.gz", hash = "sha256:9e29024bcb6ac12c220d8ea5bfe79c532c92e0c1d1170c14217165e1a8b09218"}, - {file = "boto3_stubs-1.33.10-py3-none-any.whl", hash = "sha256:61d07f445f88d5cca0a66e23dfd83611ff947bac08e01a64908df3605c22aabc"}, + {file = "boto3-stubs-1.33.11.tar.gz", hash = "sha256:0860a003b8a8bdea2df0ab182345ced6edea06721c196fb2e2e20b987716c7da"}, + {file = "boto3_stubs-1.33.11-py3-none-any.whl", hash = "sha256:5f234c6b4ee10bf233a8b55d9caa66ee1da6418a5a97fc81309583def353f858"}, ] [[package]] name = "boto3-stubs" -version = "1.33.10" +version = "1.33.11" extras = ["s3"] requires_python = ">=3.7" -summary = "Type annotations for boto3 1.33.10 generated with mypy-boto3-builder 7.21.0" +summary = "Type annotations for boto3 1.33.11 generated with mypy-boto3-builder 7.21.0" dependencies = [ - "boto3-stubs==1.33.10", + "boto3-stubs==1.33.11", "mypy-boto3-s3<1.34.0,>=1.33.0", ] files = [ - {file = "boto3-stubs-1.33.10.tar.gz", hash = "sha256:9e29024bcb6ac12c220d8ea5bfe79c532c92e0c1d1170c14217165e1a8b09218"}, - {file = "boto3_stubs-1.33.10-py3-none-any.whl", hash = "sha256:61d07f445f88d5cca0a66e23dfd83611ff947bac08e01a64908df3605c22aabc"}, + {file = "boto3-stubs-1.33.11.tar.gz", hash = "sha256:0860a003b8a8bdea2df0ab182345ced6edea06721c196fb2e2e20b987716c7da"}, + {file = "boto3_stubs-1.33.11-py3-none-any.whl", hash = "sha256:5f234c6b4ee10bf233a8b55d9caa66ee1da6418a5a97fc81309583def353f858"}, ] [[package]] name = "botocore" -version = "1.31.64" +version = "1.33.1" requires_python = ">= 3.7" summary = "Low-level, data-driven core of boto 3." dependencies = [ @@ -234,21 +234,21 @@ dependencies = [ "urllib3<2.1,>=1.25.4; python_version >= \"3.10\"", ] files = [ - {file = "botocore-1.31.64-py3-none-any.whl", hash = "sha256:7b709310343a5b430ec9025b2e17c0bac6b16c05f1ac1d9521dece3f10c71bac"}, - {file = "botocore-1.31.64.tar.gz", hash = "sha256:d8eb4b724ac437343359b318d73de0cfae0fecb24095827e56135b0ad6b44caf"}, + {file = "botocore-1.33.1-py3-none-any.whl", hash = "sha256:c744b90980786c610dd9ad9c50cf2cdde3f1c4634b954a33613f6f8a1865a1de"}, + {file = "botocore-1.33.1.tar.gz", hash = "sha256:d22d29916905e5f0670b91f07688e92b2c4a2075f9a474d6edbe7d22040d8fbf"}, ] [[package]] name = "botocore-stubs" -version = "1.33.9" +version = "1.33.11" requires_python = ">=3.7,<4.0" summary = "Type annotations and code completion for botocore" dependencies = [ "types-awscrt", ] files = [ - {file = "botocore_stubs-1.33.9-py3-none-any.whl", hash = "sha256:9d1fef0e22953102239fb3108b18588d980823ea765aef21ab861b65eba37e31"}, - {file = "botocore_stubs-1.33.9.tar.gz", hash = "sha256:60e1ace3785ecdfec5ed4bfc7c03161a5a478cd45184a4042a0238ce6f56a18a"}, + {file = "botocore_stubs-1.33.11-py3-none-any.whl", hash = "sha256:0ea9cad07310bcde284e59d470ecc06592302fa5599f912300e907e56ac51931"}, + {file = "botocore_stubs-1.33.11.tar.gz", hash = "sha256:22530caaa1a0551af6c6c35831c6c666aeb4851196ad224564415baed83b99e3"}, ] [[package]] @@ -694,7 +694,7 @@ files = [ [[package]] name = "litestar" -version = "2.4.2" +version = "2.4.3" requires_python = "<4.0,>=3.8" summary = "Litestar - A production-ready, highly performant, extensible ASGI API Framework" dependencies = [ @@ -710,13 +710,13 @@ dependencies = [ "typing-extensions", ] files = [ - {file = "litestar-2.4.2-py3-none-any.whl", hash = "sha256:562ef5075297694a428e5c162f8ec4073676ef3a4dd82279f85ede7cd88aa5b4"}, - {file = "litestar-2.4.2.tar.gz", hash = "sha256:a630ebe6575429d06b8af87dd20f2c27e91f14bcb73b6a9e5dd963e517b4891e"}, + {file = "litestar-2.4.3-py3-none-any.whl", hash = "sha256:90f0275c77e560a20adb6e07c6759478293be9545247c009c3da1f967ca4d118"}, + {file = "litestar-2.4.3.tar.gz", hash = "sha256:11cad142432636384e6fb125a78c4fc80cf5e404c3b698033c0fae2413534944"}, ] [[package]] name = "litestar" -version = "2.4.2" +version = "2.4.3" extras = ["standard"] requires_python = "<4.0,>=3.8" summary = "Litestar - A production-ready, highly performant, extensible ASGI API Framework" @@ -724,13 +724,13 @@ dependencies = [ "fast-query-parsers>=1.0.2", "jinja2", "jsbeautifier", - "litestar==2.4.2", + "litestar==2.4.3", "uvicorn[standard]", "uvloop>=0.18.0; sys_platform != \"win32\"", ] files = [ - {file = "litestar-2.4.2-py3-none-any.whl", hash = "sha256:562ef5075297694a428e5c162f8ec4073676ef3a4dd82279f85ede7cd88aa5b4"}, - {file = "litestar-2.4.2.tar.gz", hash = "sha256:a630ebe6575429d06b8af87dd20f2c27e91f14bcb73b6a9e5dd963e517b4891e"}, + {file = "litestar-2.4.3-py3-none-any.whl", hash = "sha256:90f0275c77e560a20adb6e07c6759478293be9545247c009c3da1f967ca4d118"}, + {file = "litestar-2.4.3.tar.gz", hash = "sha256:11cad142432636384e6fb125a78c4fc80cf5e404c3b698033c0fae2413534944"}, ] [[package]] @@ -869,6 +869,30 @@ files = [ {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, ] +[[package]] +name = "mypy" +version = "1.7.1" +requires_python = ">=3.8" +summary = "Optional static typing for Python" +dependencies = [ + "mypy-extensions>=1.0.0", + "typing-extensions>=4.1.0", +] +files = [ + {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, + {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, + {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, + {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, + {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, + {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, + {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, + {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, + {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, + {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, +] + [[package]] name = "mypy-boto3-s3" version = "1.33.2" @@ -882,6 +906,16 @@ files = [ {file = "mypy_boto3_s3-1.33.2-py3-none-any.whl", hash = "sha256:9d463df6def30de31a467d49ab92ff7795d46709d56eff6f52216a08bac27918"}, ] +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "packaging" version = "23.2" @@ -1237,15 +1271,15 @@ files = [ [[package]] name = "s3transfer" -version = "0.7.0" +version = "0.8.0" requires_python = ">= 3.7" summary = "An Amazon S3 Transfer Manager" dependencies = [ - "botocore<2.0a.0,>=1.12.36", + "botocore<2.0a.0,>=1.32.7", ] files = [ - {file = "s3transfer-0.7.0-py3-none-any.whl", hash = "sha256:10d6923c6359175f264811ef4bf6161a3156ce8e350e705396a7557d6293c33a"}, - {file = "s3transfer-0.7.0.tar.gz", hash = "sha256:fd3889a66f5fe17299fe75b82eae6cf722554edca744ca5d5fe308b104883d2e"}, + {file = "s3transfer-0.8.0-py3-none-any.whl", hash = "sha256:baa479dc2e63e5c2ed51611b4d46cdf0295e2070d8d0b86b22f335ee5b954986"}, + {file = "s3transfer-0.8.0.tar.gz", hash = "sha256:e8d6bd52ffd99841e3a57b34370a54841f12d3aab072af862cdcc50955288002"}, ] [[package]] @@ -1280,9 +1314,9 @@ files = [ [[package]] name = "types-aioboto3-lite" -version = "12.0.0" +version = "12.1.0" requires_python = ">=3.7" -summary = "Type annotations for aioboto3 12.0.0 generated with mypy-boto3-builder 7.19.0" +summary = "Type annotations for aioboto3 12.1.0 generated with mypy-boto3-builder 7.21.0" dependencies = [ "botocore-stubs", "types-aiobotocore-lite", @@ -1290,23 +1324,23 @@ dependencies = [ "typing-extensions>=4.1.0; python_version < \"3.12\"", ] files = [ - {file = "types-aioboto3-lite-12.0.0.tar.gz", hash = "sha256:1588120d3facdbbdbe2a755cb6d323a27a7c24b7e908c0228bb9bb42576323bd"}, - {file = "types_aioboto3_lite-12.0.0-py3-none-any.whl", hash = "sha256:ea1f76082b96b31f1333a5bce5f6038f2c220ec722fe9b84099f54ce2f4878ca"}, + {file = "types-aioboto3-lite-12.1.0.tar.gz", hash = "sha256:3b3f2a3adce6769cd1b598f81b095d69e8508717eee01f552b6add0c9071971d"}, + {file = "types_aioboto3_lite-12.1.0-py3-none-any.whl", hash = "sha256:35ce7eff72e85ee7a55b45e03e1baad8a2064c4e3c6c4e83ee2717bd49c6b864"}, ] [[package]] name = "types-aioboto3-lite" -version = "12.0.0" +version = "12.1.0" extras = ["s3"] requires_python = ">=3.7" -summary = "Type annotations for aioboto3 12.0.0 generated with mypy-boto3-builder 7.19.0" +summary = "Type annotations for aioboto3 12.1.0 generated with mypy-boto3-builder 7.21.0" dependencies = [ - "types-aioboto3-lite==12.0.0", + "types-aioboto3-lite==12.1.0", "types-aiobotocore-s3", ] files = [ - {file = "types-aioboto3-lite-12.0.0.tar.gz", hash = "sha256:1588120d3facdbbdbe2a755cb6d323a27a7c24b7e908c0228bb9bb42576323bd"}, - {file = "types_aioboto3_lite-12.0.0-py3-none-any.whl", hash = "sha256:ea1f76082b96b31f1333a5bce5f6038f2c220ec722fe9b84099f54ce2f4878ca"}, + {file = "types-aioboto3-lite-12.1.0.tar.gz", hash = "sha256:3b3f2a3adce6769cd1b598f81b095d69e8508717eee01f552b6add0c9071971d"}, + {file = "types_aioboto3_lite-12.1.0-py3-none-any.whl", hash = "sha256:35ce7eff72e85ee7a55b45e03e1baad8a2064c4e3c6c4e83ee2717bd49c6b864"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index f65c19f..ea4e63b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,9 @@ testing = [ ] linting = [ "ruff>=0.1.7", + "mypy>=1.7.1", + "types-aioboto3-lite[s3]>=12.0.0", + "boto3-stubs[s3]>=1.33.10", ] chalice = [ "chalice>=1.29.0", @@ -39,12 +42,13 @@ sls = [ requires = ["pdm-backend"] build-backend = "pdm.backend" -[tool.pdm.dev-dependencies] -dev = [ - "types-aioboto3-lite[s3]>=12.0.0", - "boto3-stubs[s3]>=1.33.10", -] - [tool.ruff] extend-select = ["W", "C90", "I", "N", "UP", "S", "BLE", "B", "A", "COM", "C4", "DTZ", "T10", "EM", "ISC", "T20", "PT", "RSE", "RET", "SIM", "PTH", "ERA", "PGH", "PL", "TRY", "RUF"] -extend-ignore = ["S101", "ISC002", "ISC002", "COM812"] \ No newline at end of file +extend-ignore = ["S101", "ISC001", "ISC002", "COM812"] + +[tool.mypy] +python_version = "3.11" +warn_return_any = true +warn_unused_configs = true +[[tool.mypy.overrides]] +module = ["aioboto3"] \ No newline at end of file diff --git a/secretsanta/domain.py b/secretsanta/domain.py index 2152ad6..458adbc 100644 --- a/secretsanta/domain.py +++ b/secretsanta/domain.py @@ -1,6 +1,7 @@ import random from abc import ABC, abstractmethod from typing import Any +from uuid import UUID from pydantic import UUID4, BaseModel @@ -31,7 +32,7 @@ class Group(BaseModel): class IRepo(ABC): @abstractmethod - async def get(self, group_uuid: str) -> Group | None: + async def get(self, group_uuid: str | UUID) -> Group | None: ... # pragma: no cover @abstractmethod @@ -45,5 +46,5 @@ class IService(ABC): self.config = config or get_config() @abstractmethod - async def run(self, *args, **kwargs) -> Any: + async def run(self, *args, **kwargs) -> Any | None: ... # pragma: no cover diff --git a/secretsanta/repo.py b/secretsanta/repo.py index 095f809..f1ff979 100644 --- a/secretsanta/repo.py +++ b/secretsanta/repo.py @@ -1,5 +1,6 @@ import json from contextlib import asynccontextmanager +from uuid import UUID import aioboto3 from botocore.exceptions import ClientError @@ -26,7 +27,7 @@ class S3Repo(IRepo): async with self.session.client("s3", **kwargs) as s3: yield s3 - async def get(self, group_uuid: str) -> Group | None: + async def get(self, group_uuid: str | UUID) -> Group | None: async with self.get_s3() as s3: try: s3_obj = await s3.get_object( diff --git a/secretsanta/service.py b/secretsanta/service.py index 3f5028e..958ddca 100644 --- a/secretsanta/service.py +++ b/secretsanta/service.py @@ -3,7 +3,9 @@ from uuid import UUID from secretsanta.domain import Group, IService -def participants2url(participants: list[str], group_uuid: str | UUID, server_url: str): +def participants2url( + participants: list[str], group_uuid: str | UUID, server_url: str +) -> list[str]: return [ f"{server_url}/groups/{group_uuid}/pair/{participant}" for participant in participants @@ -11,7 +13,7 @@ def participants2url(participants: list[str], group_uuid: str | UUID, server_url class CreateGroupService(IService): - async def run(self, group: Group): + async def run(self, group: Group) -> list[str]: if existing_group := await self.repo.get(group.uuid): return participants2url( participants=existing_group.participants, @@ -42,6 +44,9 @@ class GetGroupParticipantsService(IService): class GetPairService(IService): - async def run(self, group_uuid: str, participant: str) -> str: + async def run(self, group_uuid: str, participant: str) -> str | None: group = await self.repo.get(group_uuid) + if not group or not group.pairs: + return None + return group.pairs[participant]