diff --git a/.github/workflows/code_quality.yaml b/.github/workflows/code_quality.yaml
index 4fb33dcf0ad..7ac55ad1033 100644
--- a/.github/workflows/code_quality.yaml
+++ b/.github/workflows/code_quality.yaml
@@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v3
with:
- python-version: "3.11"
+ python-version: "3.13"
- name: Install git-secrets in the repository
run: git secrets --install
- name: Install git-secrets aws register in the repository
diff --git a/Pipfile b/Pipfile
index b1f3437676e..dcc39651404 100644
--- a/Pipfile
+++ b/Pipfile
@@ -7,21 +7,21 @@ name = "pypi"
aio-pika = "==9.5.*"
aiofiles = "==24.1.0"
aiohttp = "==3.11.*"
-alembic = "==1.14.0"
+alembic = "==1.14.*"
asyncpg = "==0.30.0"
-azure-storage-blob = "==12.24.0"
+azure-storage-blob = "==12.24.*"
bcrypt = "==4.2.1"
-boto3 = "==1.35.*"
-fastapi = "==0.115.6"
+boto3 = "==1.36.*"
+fastapi = "==0.115.*"
fastapi-mail = "==1.2.9"
firebase-admin = "==6.6.*"
httpx = "==0.28.*"
jinja2 = "==3.1.*"
-more-itertools = "==10.5.0"
+more-itertools = "==10.6.0"
nh3 = "==0.2.20"
pydantic = { extras = ["email"], version = "==1.10.18" }
pyjwt = "==2.10.1"
-pymongo = "==4.10.1"
+pymongo = "==4.10.*"
pyOpenSSL = "==24.3.*"
python-multipart = "==0.0.20"
redis = "==5.2.*"
@@ -34,9 +34,9 @@ taskiq-fastapi = "==0.3.*"
taskiq-redis = "==1.0.2"
typer = "==0.15.*"
uvicorn = { extras = ["standard"], version = "==0.34.*" }
-ddtrace = "==2.*"
-bytecode = "==0.16.0"
-structlog = "==24.4.0"
+ddtrace = "==2.20.*"
+bytecode = "==0.16.*"
+structlog = "==25.1.*"
asgi-correlation-id = "==4.3.4"
@@ -48,7 +48,7 @@ greenlet = "==3.1.0"
ipdb = "==0.13.13"
mypy = "==1.14.*"
nest-asyncio = "==1.6.0"
-pre-commit = "==4.0.1"
+pre-commit = "==4.1.*"
pudb = "==2024.1.3"
pydantic-factories = "==1.17.3"
pyld = "==2.0.4"
@@ -59,7 +59,7 @@ pytest-env = "==1.1.5"
pytest-lazy-fixtures = "==1.*"
pytest-mock = "==3.14.0"
reproschema = "==0.6.2"
-ruff = "==0.8.*"
+ruff = "==0.9.*"
types-aiofiles = "==24.1.0.*"
types-cachetools = "==5.5.0.*"
types-python-dateutil = "==2.9.0.*"
@@ -68,7 +68,7 @@ types-requests = "==2.32.0.*"
typing-extensions = "==4.12.2"
[requires]
-python_version = "3.11"
+python_version = "3.13"
[scripts]
cli = "python src/cli.py"
diff --git a/Pipfile.lock b/Pipfile.lock
index fe8d76ee153..59efbb16bc1 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
- "sha256": "8f6ddb51c19b553ae0a1620249458e40183c146dece2511ae1b13ef076bce772"
+ "sha256": "586603f2208e3db6273f22cd99d4481bcb484bd23a82a73f213c4e0fad1d9b73"
},
"pipfile-spec": 6,
"requires": {
- "python_version": "3.11"
+ "python_version": "3.13"
},
"sources": [
{
@@ -151,12 +151,12 @@
},
"alembic": {
"hashes": [
- "sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25",
- "sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b"
+ "sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5",
+ "sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==1.14.0"
+ "version": "==1.14.1"
},
"anyio": {
"hashes": [
@@ -249,12 +249,12 @@
},
"azure-storage-blob": {
"hashes": [
- "sha256:4f0bb4592ea79a2d986063696514c781c9e62be240f09f6397986e01755bc071",
- "sha256:eaaaa1507c8c363d6e1d1342bd549938fdf1adec9b1ada8658c8f5bf3aea844e"
+ "sha256:052b2a1ea41725ba12e2f4f17be85a54df1129e13ea0321f5a2fcc851cbf47d4",
+ "sha256:77fb823fdbac7f3c11f7d86a5892e2f85e161e8440a7489babe2195bf248f09e"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==12.24.0"
+ "version": "==12.24.1"
},
"bcrypt": {
"hashes": [
@@ -298,29 +298,29 @@
},
"boto3": {
"hashes": [
- "sha256:83e560faaec38a956dfb3d62e05e1703ee50432b45b788c09e25107c5058bd71",
- "sha256:e0abd794a7a591d90558e92e29a9f8837d25ece8e3c120e530526fe27eba5fca"
+ "sha256:641dd772eac111d9443258f0f5491c57c2af47bddae94a8d32de19edb5bf7b1c",
+ "sha256:b40fbf2c0f22e55b67df95475a68bb72be5169097180a875726b6b884339ac8b"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==1.35.99"
+ "version": "==1.36.11"
},
"botocore": {
"hashes": [
- "sha256:1eab44e969c39c5f3d9a3104a0836c24715579a455f12b3979a31d7cde51b3c3",
- "sha256:b22d27b6b617fc2d7342090d6129000af2efd20174215948c0d7ae2da0fab445"
+ "sha256:82c5660027f696608d0e55feb08c146c11c7ebeba7615961c7765dcf6009a00d",
+ "sha256:c919be883f95b9e0c3021429a365d40cd7944b8345a07af30dc8d891ceefe07a"
],
"markers": "python_version >= '3.8'",
- "version": "==1.35.99"
+ "version": "==1.36.11"
},
"bytecode": {
"hashes": [
- "sha256:06676a3c3bccc9d3dc73ee625650ea57df2bc117358826f4f290f0e1faa42292",
- "sha256:76080b7c0eb9e7e17f961d61fd06e933aa47f3b753770a3249537439d8203a25"
+ "sha256:1d4b61ed6bade4bff44127c8283bef8131a664ce4dbe09d64a88caf329939f35",
+ "sha256:8fbbb637c880f339e564858bc6c7984ede67ae97bc71343379a535a9a4baf398"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==0.16.0"
+ "version": "==0.16.1"
},
"cachecontrol": {
"hashes": [
@@ -340,11 +340,11 @@
},
"certifi": {
"hashes": [
- "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
- "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
+ "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
+ "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"
],
"markers": "python_version >= '3.6'",
- "version": "==2024.12.14"
+ "version": "==2025.1.31"
},
"cffi": {
"hashes": [
@@ -675,12 +675,12 @@
},
"fastapi": {
"hashes": [
- "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654",
- "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"
+ "sha256:0ce9111231720190473e222cdf0f07f7206ad7e53ea02beb1d2dc36e2f0741e9",
+ "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==0.115.6"
+ "version": "==0.115.8"
},
"fastapi-mail": {
"hashes": [
@@ -856,11 +856,11 @@
},
"google-cloud-storage": {
"hashes": [
- "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba",
- "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2"
+ "sha256:2accb3e828e584888beff1165e5f3ac61aa9088965eb0165794a82d8c7f95297",
+ "sha256:f85fd059650d2dbb0ac158a9a6b304b66143b35ed2419afec2905ca522eb2c6a"
],
"markers": "python_version >= '3.7'",
- "version": "==2.19.0"
+ "version": "==3.0.0"
},
"google-crc32c": {
"hashes": [
@@ -1182,6 +1182,14 @@
"markers": "python_version >= '3.7'",
"version": "==1.0.1"
},
+ "legacy-cgi": {
+ "hashes": [
+ "sha256:9952471ceb304043b104c22d00b4f333cac27a6abe446d8a528fc437cf13c85f",
+ "sha256:a7b83afb1baf6ebeb56522537c5943ef9813cf933f6715e88a803f7edbce0bff"
+ ],
+ "markers": "python_version >= '3.10'",
+ "version": "==2.6.2"
+ },
"mako": {
"hashes": [
"sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627",
@@ -1275,12 +1283,12 @@
},
"more-itertools": {
"hashes": [
- "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef",
- "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"
+ "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b",
+ "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"
],
"index": "pypi",
- "markers": "python_version >= '3.8'",
- "version": "==10.5.0"
+ "markers": "python_version >= '3.9'",
+ "version": "==10.6.0"
},
"msgpack": {
"hashes": [
@@ -1832,10 +1840,10 @@
},
"pytz": {
"hashes": [
- "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a",
- "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"
+ "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57",
+ "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"
],
- "version": "==2024.2"
+ "version": "==2025.1"
},
"pyyaml": {
"hashes": [
@@ -1931,11 +1939,11 @@
},
"s3transfer": {
"hashes": [
- "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e",
- "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"
+ "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f",
+ "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc"
],
"markers": "python_version >= '3.8'",
- "version": "==0.10.4"
+ "version": "==0.11.2"
},
"sentry-sdk": {
"hashes": [
@@ -2034,20 +2042,20 @@
},
"starlette": {
"hashes": [
- "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835",
- "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"
+ "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f",
+ "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d"
],
- "markers": "python_version >= '3.8'",
- "version": "==0.41.3"
+ "markers": "python_version >= '3.9'",
+ "version": "==0.45.3"
},
"structlog": {
"hashes": [
- "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610",
- "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"
+ "sha256:2ef2a572e0e27f09664965d31a576afe64e46ac6084ef5cec3c2b8cd6e4e3ad3",
+ "sha256:843fe4f254540329f380812cbe612e1af5ec5b8172205ae634679cd35a6d6321"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==24.4.0"
+ "version": "==25.1.0"
},
"taskiq": {
"extras": [
@@ -2616,11 +2624,11 @@
},
"certifi": {
"hashes": [
- "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
- "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
+ "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
+ "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"
],
"markers": "python_version >= '3.6'",
- "version": "==2024.12.14"
+ "version": "==2025.1.31"
},
"cfgv": {
"hashes": [
@@ -2847,11 +2855,11 @@
},
"faker": {
"hashes": [
- "sha256:42f2da8cf561e38c72b25e9891168b1e25fec42b6b0b5b0b6cd6041da54af885",
- "sha256:926d2301787220e0554c2e39afc4dc535ce4b0a8d0a089657137999f66334ef4"
+ "sha256:28c24061780f83b45d9cb15a72b8f143b09d276c9ff52eb557744b7a89e8ba19",
+ "sha256:609abe555761ff31b0e5e16f958696e9b65c9224a7ac612ac96bfc2b8f09fe35"
],
"markers": "python_version >= '3.8'",
- "version": "==35.0.0"
+ "version": "==35.2.0"
},
"filelock": {
"hashes": [
@@ -3057,14 +3065,6 @@
"markers": "python_version >= '3.6'",
"version": "==3.10"
},
- "importlib-metadata": {
- "hashes": [
- "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b",
- "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"
- ],
- "markers": "python_version >= '3.8'",
- "version": "==8.5.0"
- },
"iniconfig": {
"hashes": [
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
@@ -3084,11 +3084,11 @@
},
"ipython": {
"hashes": [
- "sha256:46ec58f8d3d076a61d128fe517a51eb730e3aaf0c184ea8c17d16e366660c6a6",
- "sha256:b6a2274606bec6166405ff05e54932ed6e5cfecaca1fc05f2cacde7bb074d70b"
+ "sha256:be2c91895b0b9ea7ba49d33b23e2040c352b33eb6a519cca7ce6e0c743444251",
+ "sha256:cae85b0c61eff1fc48b0a8002de5958b6528fa9c8defb1894da63f42613708aa"
],
"markers": "python_version >= '3.10'",
- "version": "==8.31.0"
+ "version": "==8.32.0"
},
"jedi": {
"hashes": [
@@ -3370,20 +3370,20 @@
},
"pre-commit": {
"hashes": [
- "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2",
- "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"
+ "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4",
+ "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
- "version": "==4.0.1"
+ "version": "==4.1.0"
},
"prettytable": {
"hashes": [
- "sha256:30e1a097a7acb075b5c488ffe01195349b37009c2d43ca7fa8b5f6a61daace5b",
- "sha256:d4f5817a248b77ddaa25b27007566c0a6a064308d991516b61b436ffdbb4f8e9"
+ "sha256:61d5c68f04a94acc73c7aac64f0f380f5bed4d2959d59edc6e4cbb7a0e7b55c4",
+ "sha256:b804b8d51db23959b96b329094debdbbdf10c8c3aa75958c5988cfd7f78501dd"
],
"markers": "python_version >= '3.9'",
- "version": "==3.13.0"
+ "version": "==3.14.0"
},
"prompt-toolkit": {
"hashes": [
@@ -3667,28 +3667,28 @@
},
"ruff": {
"hashes": [
- "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25",
- "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe",
- "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75",
- "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a",
- "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76",
- "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188",
- "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1",
- "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf",
- "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117",
- "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162",
- "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d",
- "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d",
- "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315",
- "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5",
- "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3",
- "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764",
- "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807",
- "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905"
+ "sha256:05bebf4cdbe3ef75430d26c375773978950bbf4ee3c95ccb5448940dc092408e",
+ "sha256:1d4c8772670aecf037d1bf7a07c39106574d143b26cfe5ed1787d2f31e800214",
+ "sha256:37c892540108314a6f01f105040b5106aeb829fa5fb0561d2dcaf71485021137",
+ "sha256:433dedf6ddfdec7f1ac7575ec1eb9844fa60c4c8c2f8887a070672b8d353d34c",
+ "sha256:54499fb08408e32b57360f6f9de7157a5fec24ad79cb3f42ef2c3f3f728dfe2b",
+ "sha256:56acd6c694da3695a7461cc55775f3a409c3815ac467279dfa126061d84b314b",
+ "sha256:585792f1e81509e38ac5123492f8875fbc36f3ede8185af0a26df348e5154f41",
+ "sha256:64e73d25b954f71ff100bb70f39f1ee09e880728efb4250c632ceed4e4cdf706",
+ "sha256:6907ee3529244bb0ed066683e075f09285b38dd5b4039370df6ff06041ca19e7",
+ "sha256:6ce6743ed64d9afab4fafeaea70d3631b4d4b28b592db21a5c2d1f0ef52934bf",
+ "sha256:87c90c32357c74f11deb7fbb065126d91771b207bf9bfaaee01277ca59b574ec",
+ "sha256:a6c634fc6f5a0ceae1ab3e13c58183978185d131a29c425e4eaa9f40afe1e6d6",
+ "sha256:bfc5f1d7afeda8d5d37660eeca6d389b142d7f2b5a1ab659d9214ebd0e025231",
+ "sha256:d612dbd0f3a919a8cc1d12037168bfa536862066808960e0cc901404b77968f0",
+ "sha256:db1192ddda2200671f9ef61d9597fcef89d934f5d1705e571a93a67fb13a4402",
+ "sha256:de9edf2ce4b9ddf43fd93e20ef635a900e25f622f87ed6e3047a664d0e8f810e",
+ "sha256:e0c93e7d47ed951b9394cf352d6695b31498e68fd5782d6cbc282425655f687a",
+ "sha256:faa935fc00ae854d8b638c16a5f1ce881bc3f67446957dd6f2af440a5fc8526b"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
- "version": "==0.8.6"
+ "version": "==0.9.4"
},
"setuptools": {
"hashes": [
@@ -3819,14 +3819,6 @@
],
"version": "==0.2.13"
},
- "zipp": {
- "hashes": [
- "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4",
- "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"
- ],
- "markers": "python_version >= '3.9'",
- "version": "==3.21.0"
- },
"zope.event": {
"hashes": [
"sha256:2832e95014f4db26c47a13fdaef84cef2f4df37e66b59d8f1f4a8f319a632c26",
diff --git a/README.md b/README.md
index ec8177fac0a..28a6cb7063f 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ See MindLogger's [Knowledge Base article](https://mindlogger.atlassian.net/servi
## Technologies
-- ✅ [Python3.11+](https://www.python.org/downloads/release/python-31110/)
+- ✅ [Python 3.13](https://www.python.org/downloads/release/python-3132/)
- ✅ [Pipenv](https://pipenv.pypa.io/en/latest/)
- ✅ [FastAPI](https://fastapi.tiangolo.com)
- ✅ [Postgresql](https://www.postgresql.org/docs/14/index.html)
@@ -61,7 +61,7 @@ And
### Prerequisites
-- Python 3.11
+- Python 3.13
- [Docker](https://docs.docker.com/get-docker/)
#### Recommended Extras
@@ -71,7 +71,7 @@ Installing [pyenv](https://github.com/pyenv/pyenv) is recommended to automatical
Alternatively, on macOS you can use a tool like [Homebrew](https://brew.sh/) to install multiple versions and specify when creating the virtual environment:
```bash
-pipenv --python /opt/homebrew/bin/python3.11
+pipenv --python /opt/homebrew/bin/python3.13
```
### Environment Variables
@@ -189,15 +189,15 @@ Create your virtual environment:
pipenv shell
```
-If `pyenv` is installed Python 3.11 should automatically be installed in the virtual environment, you can check the
+If `pyenv` is installed Python 3.13 should automatically be installed in the virtual environment, you can check the
correct version of Python is active by running:
```bash
python --version
```
-If the active version is **not** 3.11, you can manually specify a version while creating your virtual environment:
+If the active version is **not** 3.13, you can manually specify a version while creating your virtual environment:
```bash
-pipenv --python /opt/homebrew/bin/python3.11
+pipenv --python /opt/homebrew/bin/python3.13
```
Install all dependencies
diff --git a/compose/fastapi/Dockerfile b/compose/fastapi/Dockerfile
index 5b278bf96f0..2b700ffb875 100644
--- a/compose/fastapi/Dockerfile
+++ b/compose/fastapi/Dockerfile
@@ -1,4 +1,4 @@
-FROM python:3.11-slim-bookworm AS base
+FROM python:3.13-slim-bookworm AS base
ENV PYTHONUNBUFFERED=1
ENV PYTHONPATH="src/"
diff --git a/conftest.py b/conftest.py
index ef485f59048..9ad7d3b0e81 100644
--- a/conftest.py
+++ b/conftest.py
@@ -61,12 +61,12 @@ async def global_session(global_engine: AsyncEngine):
# TODO: Instead of custom faketime for tests add function wrapper `now`
-# to use it instead of builtin datetime.datetime.utcnow
+# to use it instead of builtin datetime.datetime.now
class FakeTime(datetime.datetime):
current_utc = datetime.datetime(2024, 1, 1, 0, 0, 0)
@classmethod
- def utcnow(cls):
+ def now(cls, tzinfo=None):
return cls.current_utc
diff --git a/pyproject.toml b/pyproject.toml
index d02572f6f95..ab49cff9f42 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -73,7 +73,7 @@ omit = [
[tool.mypy]
plugins = ["pydantic.mypy"]
ignore_missing_imports = true
-python_version = '3.11'
+python_version = '3.13'
mypy_path = 'src'
files = ['*.py']
warn_redundant_casts = true
diff --git a/src/apps/activities/domain/constants_ab_trails_mobile.py b/src/apps/activities/domain/constants_ab_trails_mobile.py
index 6052f2c5608..cc1a779e055 100644
--- a/src/apps/activities/domain/constants_ab_trails_mobile.py
+++ b/src/apps/activities/domain/constants_ab_trails_mobile.py
@@ -75,13 +75,12 @@
MOBILE_TUTORIALS_FIRST: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers in circles on this screen."),
- Tutorial(text="You will take a pen and draw a line from one number " "to the next, in order."),
+ Tutorial(text="You will take a pen and draw a line from one number to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="Then go to 2.", node_label="2"),
Tutorial(text="Then 3, and so on.", node_label="3"),
Tutorial(
- text="Please try not to lift the pen as you move from one "
- "number to the next. Work as quickly as you can."
+ text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="11"),
@@ -92,10 +91,10 @@
MOBILE_TUTORIALS_SECOND: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="On this screen are more numbers in circles."),
- Tutorial(text="You will take a pen and draw a line from one circle " "to the next, in order."),
+ Tutorial(text="You will take a pen and draw a line from one circle to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And End here.", node_label="11"),
- Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
+ Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
@@ -106,14 +105,13 @@
MOBILE_TUTORIALS_THIRD: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers and letters in circles on this screen."),
- Tutorial(text="You will take a pen and draw a line alternating in " "order between the numbers and letters."),
+ Tutorial(text="You will take a pen and draw a line alternating in order between the numbers and letters."),
Tutorial(text="Start at number 1.", node_label="1"),
Tutorial(text="Then go to the first letter A.", node_label="A"),
Tutorial(text="Then go to the next number 2.", node_label="2"),
Tutorial(text="Then go to the next letter B, and so on.", node_label="B"),
Tutorial(
- text="Please try not to lift the pen as you move from one "
- "number to the next. Work as quickly as you can."
+ text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="6"),
@@ -125,12 +123,12 @@
MOBILE_TUTORIALS_FOURTH: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
- Tutorial(text="On this screen there are more numbers and letters " "in circles."),
- Tutorial(text="You will take a pen and draw a line from one circle " "to the next."),
+ Tutorial(text="On this screen there are more numbers and letters in circles."),
+ Tutorial(text="You will take a pen and draw a line from one circle to the next."),
Tutorial(text="Alternating in order between the numbers and letters."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And end here.", node_label="6"),
- Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
+ Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
diff --git a/src/apps/activities/domain/constants_ab_trails_tablet.py b/src/apps/activities/domain/constants_ab_trails_tablet.py
index d2217ff8b5e..76467e42f22 100644
--- a/src/apps/activities/domain/constants_ab_trails_tablet.py
+++ b/src/apps/activities/domain/constants_ab_trails_tablet.py
@@ -109,13 +109,12 @@
TABLET_TUTORIALS_FIRST: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers in circles on this screen."),
- Tutorial(text="You will take a pen and draw a line from one number " "to the next, in order."),
+ Tutorial(text="You will take a pen and draw a line from one number to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="Then go to 2.", node_label="2"),
Tutorial(text="Then 3, and so on.", node_label="3"),
Tutorial(
- text="Please try not to lift the pen as you move from one "
- "number to the next. Work as quickly as you can."
+ text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="8"),
@@ -126,10 +125,10 @@
TABLET_TUTORIALS_SECOND: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="On this screen are more numbers in circles."),
- Tutorial(text="You will take a pen and draw a line from one circle to " "the next, in order."),
+ Tutorial(text="You will take a pen and draw a line from one circle to the next, in order."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And End here.", node_label="25"),
- Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
+ Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
@@ -140,14 +139,13 @@
TABLET_TUTORIALS_THIRD: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
Tutorial(text="There are numbers and letters in circles on this screen."),
- Tutorial(text="You will take a pen and draw a line alternating in " "order between the numbers and letters."),
+ Tutorial(text="You will take a pen and draw a line alternating in order between the numbers and letters."),
Tutorial(text="Start at number 1.", node_label="1"),
Tutorial(text="Then go to the first letter A.", node_label="A"),
Tutorial(text="Then go to the next number 2.", node_label="2"),
Tutorial(text="Then go to the next letter B, and so on.", node_label="B"),
Tutorial(
- text="Please try not to lift the pen as you move from one "
- "number to the next. Work as quickly as you can."
+ text="Please try not to lift the pen as you move from one number to the next. Work as quickly as you can."
),
Tutorial(text="Begin here.", node_label="1"),
Tutorial(text="And end here.", node_label="D"),
@@ -159,12 +157,12 @@
TABLET_TUTORIALS_FOURTH: ABTrailsTutorial = ABTrailsTutorial(
tutorials=[
- Tutorial(text="On this screen there are more numbers and letters " "in circles."),
- Tutorial(text="You will take a pen and draw a line from one circle " "to the next."),
+ Tutorial(text="On this screen there are more numbers and letters in circles."),
+ Tutorial(text="You will take a pen and draw a line from one circle to the next."),
Tutorial(text="Alternating in order between the numbers and letters."),
Tutorial(text="Start at 1.", node_label="1"),
Tutorial(text="And end here.", node_label="13"),
- Tutorial(text="Please try not to lift the pen as you move from one " "circle to the next."),
+ Tutorial(text="Please try not to lift the pen as you move from one circle to the next."),
Tutorial(text="Work as quickly as you can."),
Tutorial(
text="Click next to start",
diff --git a/src/apps/activities/errors.py b/src/apps/activities/errors.py
index a7a5b8d7484..f18b5a64fe5 100644
--- a/src/apps/activities/errors.py
+++ b/src/apps/activities/errors.py
@@ -94,7 +94,7 @@ class InvalidDataMatrixByOptionError(FieldError):
class InvalidScoreLengthError(FieldError):
- message = _("Scores must have the same length as the " "range of min_value and max_value")
+ message = _("Scores must have the same length as the range of min_value and max_value")
class ActivityAccessDeniedError(AccessDeniedError):
diff --git a/src/apps/activities/tests/test_activities.py b/src/apps/activities/tests/test_activities.py
index f558c5bc066..198ead5bf73 100644
--- a/src/apps/activities/tests/test_activities.py
+++ b/src/apps/activities/tests/test_activities.py
@@ -636,7 +636,7 @@ async def test_activities_applet_has_score(
en="Understand how was the morning",
fr="Understand how was the morning",
),
- items=[dict(activity_key="577dbbda-3afc-" "4962-842b-8d8d11588bfe")],
+ items=[dict(activity_key="577dbbda-3afc-4962-842b-8d8d11588bfe")],
)
],
)
diff --git a/src/apps/activities/tests/unit/test_activity_change.py b/src/apps/activities/tests/unit/test_activity_change.py
index db6b594870f..6330ecf0a0c 100644
--- a/src/apps/activities/tests/unit/test_activity_change.py
+++ b/src/apps/activities/tests/unit/test_activity_change.py
@@ -117,7 +117,7 @@ def old_activity(activity_history_id: uuid.UUID, old_applet_id: str, old_id_vers
is_reviewable=False,
response_is_editable=False,
order=1,
- created_at=datetime.datetime.utcnow(),
+ created_at=datetime.datetime.now(datetime.UTC),
is_hidden=False,
)
@@ -137,7 +137,7 @@ def new_activity(activity_history_id: uuid.UUID, new_applet_id: str, new_version
is_reviewable=False,
response_is_editable=False,
order=1,
- created_at=datetime.datetime.utcnow(),
+ created_at=datetime.datetime.now(datetime.UTC),
is_hidden=False,
)
diff --git a/src/apps/activities/tests/unit/test_activity_item_change.py b/src/apps/activities/tests/unit/test_activity_item_change.py
index 64fd84ebba6..b08db0cd9f7 100644
--- a/src/apps/activities/tests/unit/test_activity_item_change.py
+++ b/src/apps/activities/tests/unit/test_activity_item_change.py
@@ -342,7 +342,7 @@ def test_conditional_logic_added(conditional_logic: ConditionalLogic):
condition_type = condition.type.lower().replace("_", " ")
item_name = condition.item_name
value = condition.payload.value # type: ignore
- assert changes == [f"{parent_name}: If All: " f"{item_name} {condition_type} {value} was added"]
+ assert changes == [f"{parent_name}: If All: {item_name} {condition_type} {value} was added"]
def test_conditional_logic_changed(conditional_logic: ConditionalLogic):
@@ -356,9 +356,7 @@ def test_conditional_logic_changed(conditional_logic: ConditionalLogic):
condition_type = condition.type.lower().replace("_", " ")
item_name = condition.item_name
value = condition.payload.value # type: ignore
- assert changes == [
- f"{parent_name}: If {new.match.capitalize()}: " f"{item_name} {condition_type} {value} was updated"
- ]
+ assert changes == [f"{parent_name}: If {new.match.capitalize()}: {item_name} {condition_type} {value} was updated"]
def test_conditional_logic_removed(
diff --git a/src/apps/activity_assignments/crud/assignments.py b/src/apps/activity_assignments/crud/assignments.py
index 1ee90e151c1..342fe7e3d12 100644
--- a/src/apps/activity_assignments/crud/assignments.py
+++ b/src/apps/activity_assignments/crud/assignments.py
@@ -288,7 +288,7 @@ async def upsert(self, values: dict) -> ActivityAssigmentSchema | None:
else ActivityAssigmentSchema.activity_flow_id,
],
set_={
- "updated_at": datetime.datetime.utcnow(),
+ "updated_at": datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
"is_deleted": False,
},
where=(ActivityAssigmentSchema.soft_exists(exists=False)),
diff --git a/src/apps/answers/router.py b/src/apps/answers/router.py
index a123366e792..a5f45bf8ed3 100644
--- a/src/apps/answers/router.py
+++ b/src/apps/answers/router.py
@@ -330,7 +330,7 @@
)(answer_note_list)
router.put(
- "/applet/{applet_id}/answers/{answer_id}/activities/" "{activity_id}/notes/{note_id}",
+ "/applet/{applet_id}/answers/{answer_id}/activities/{activity_id}/notes/{note_id}",
# noqa: E501
status_code=status.HTTP_200_OK,
responses={
@@ -340,7 +340,7 @@
)(answer_note_edit)
router.delete(
- "/applet/{applet_id}/answers/{answer_id}/activities/" "{activity_id}/notes/{note_id}",
+ "/applet/{applet_id}/answers/{answer_id}/activities/{activity_id}/notes/{note_id}",
# noqa: E501
status_code=status.HTTP_204_NO_CONTENT,
responses={
diff --git a/src/apps/answers/service.py b/src/apps/answers/service.py
index c468a624b11..9df048fbc43 100644
--- a/src/apps/answers/service.py
+++ b/src/apps/answers/service.py
@@ -308,7 +308,7 @@ async def _get_answer_relation(
async def _create_answer(self, applet_answer: AppletAnswerCreate) -> AnswerSchema:
assert self.user_id
pk = self._generate_history_id(applet_answer.version)
- created_at = applet_answer.created_at or datetime.datetime.utcnow()
+ created_at = applet_answer.created_at or datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
subject_crud = SubjectsCrud(self.session)
respondent_subject = await subject_crud.get_user_subject(
@@ -1036,21 +1036,21 @@ async def create_assessment_answer(
AnswerItemSchema(
id=assessment.id,
created_at=assessment.created_at,
- updated_at=datetime.datetime.utcnow(),
+ updated_at=datetime.datetime.now(datetime.UTC),
answer_id=answer_id,
respondent_id=self.user_id,
answer=schema.answer,
item_ids=list(map(str, schema.item_ids)),
user_public_key=schema.reviewer_public_key,
is_assessment=True,
- start_datetime=datetime.datetime.utcnow(),
- end_datetime=datetime.datetime.utcnow(),
+ start_datetime=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
+ end_datetime=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
assessment_activity_id=schema.assessment_version_id,
reviewed_flow_submit_id=submit_id,
)
)
else:
- now = datetime.datetime.utcnow()
+ now = datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
await AnswerItemsCRUD(self.answer_session).create(
AnswerItemSchema(
answer_id=answer_id,
@@ -2136,7 +2136,7 @@ async def create_report(
data = dict(
responses=responses,
- now=datetime.datetime.utcnow().strftime("%x"),
+ now=datetime.datetime.now(datetime.UTC).strftime("%x"),
user=user_info,
applet=applet_full,
)
@@ -2268,12 +2268,12 @@ async def decrypt_data_for_loris(
) as resp:
duration = time.time() - start
if resp.status == 200:
- logger.info(f"Successful request (for LORIS) in {duration:.1f}" " seconds.")
+ logger.info(f"Successful request (for LORIS) in {duration:.1f} seconds.")
response_data = await resp.json()
# return ReportServerResponse(**response_data)
return response_data, answer_versions
else:
- logger.error(f"Failed request (for LORIS) in {duration:.1f}" " seconds.")
+ logger.error(f"Failed request (for LORIS) in {duration:.1f} seconds.")
error_message = await resp.text()
raise ReportServerError(message=error_message)
diff --git a/src/apps/answers/tests/conftest.py b/src/apps/answers/tests/conftest.py
index 82f03c8687f..e511bbac1bb 100644
--- a/src/apps/answers/tests/conftest.py
+++ b/src/apps/answers/tests/conftest.py
@@ -215,9 +215,9 @@ def answer_item_create(
identifier="encrypted_identifier",
scheduled_time=None,
scheduled_event_id=str(uuid.uuid4()),
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow() + datetime.timedelta(seconds=1),
- local_end_date=datetime.datetime.utcnow().date() - datetime.timedelta(days=1),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC) + datetime.timedelta(seconds=1),
+ local_end_date=datetime.datetime.now(datetime.UTC).date() - datetime.timedelta(days=1),
local_end_time=datetime.time(15, 0),
user_public_key="public_key",
)
@@ -235,7 +235,7 @@ def answer_create(
submit_id=uuid.uuid4(),
activity_id=applet.activities[0].id,
answer=answer_item_create,
- created_at=datetime.datetime.utcnow().replace(microsecond=0),
+ created_at=datetime.datetime.now(datetime.UTC).replace(microsecond=0),
client=client_meta,
consent_to_share=False,
)
@@ -253,7 +253,7 @@ def answer_create_applet_one(
submit_id=uuid.uuid4(),
activity_id=applet_one.activities[0].id,
answer=answer_item_create,
- created_at=datetime.datetime.utcnow().replace(microsecond=0),
+ created_at=datetime.datetime.now(datetime.UTC).replace(microsecond=0),
client=client_meta,
)
@@ -276,7 +276,7 @@ def answer_with_alert_create(
submit_id=uuid.uuid4(),
activity_id=applet.activities[0].id,
answer=answer_item_create,
- created_at=datetime.datetime.utcnow().replace(microsecond=0),
+ created_at=datetime.datetime.now(datetime.UTC).replace(microsecond=0),
client=client_meta,
alerts=[answer_alert],
consent_to_share=False,
@@ -302,7 +302,7 @@ def public_answer_create(
submit_id=uuid.uuid4(),
activity_id=public_applet.activities[0].id,
answer=item_create,
- created_at=datetime.datetime.utcnow().replace(microsecond=0),
+ created_at=datetime.datetime.now(datetime.UTC).replace(microsecond=0),
client=client_meta,
consent_to_share=False,
)
@@ -320,7 +320,7 @@ def answer_with_flow_create(
submit_id=uuid.uuid4(),
activity_id=applet.activities[0].id,
answer=answer_item_create,
- created_at=datetime.datetime.utcnow().replace(microsecond=0),
+ created_at=datetime.datetime.now(datetime.UTC).replace(microsecond=0),
client=client_meta,
flow_id=applet.activity_flows[0].id,
is_flow_completed=True,
@@ -353,7 +353,7 @@ def answer_reviewable_activity_create(
submit_id=uuid.uuid4(),
activity_id=activity.id,
answer=item_create,
- created_at=datetime.datetime.utcnow().replace(microsecond=0),
+ created_at=datetime.datetime.now(datetime.UTC).replace(microsecond=0),
client=client_meta,
consent_to_share=False,
)
@@ -513,8 +513,8 @@ def tom_answer_create_data(tom, applet_with_reviewable_activity) -> AppletAnswer
activity_id=applet_with_reviewable_activity.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet_with_reviewable_activity.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
),
client=ClientMeta(app_id=f"{uuid.uuid4()}", app_version="1.1", width=984, height=623),
@@ -593,7 +593,7 @@ def answers_reviewable_submission_create(
submit_id=submit_id,
activity_id=activity.id,
answer=item_create,
- created_at=datetime.datetime.utcnow().replace(microsecond=0),
+ created_at=datetime.datetime.now(datetime.UTC).replace(microsecond=0),
client=client_meta,
flow_id=applet_with_reviewable_flow.activity_flows[0].id,
)
diff --git a/src/apps/answers/tests/test_answers.py b/src/apps/answers/tests/test_answers.py
index 9aaf629d2a3..574ba3ee05c 100644
--- a/src/apps/answers/tests/test_answers.py
+++ b/src/apps/answers/tests/test_answers.py
@@ -184,8 +184,8 @@ async def tom_answer_item_for_applet(tom: User, applet: AppletFull, session: Asy
respondent_id=tom.id,
answer=uuid.uuid4().hex,
item_ids=[str(item.id) for item in applet.activities[0].items],
- start_datetime=datetime.datetime.utcnow(),
- end_datetime=datetime.datetime.utcnow(),
+ start_datetime=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
+ end_datetime=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
is_assessment=False,
)
@@ -211,8 +211,8 @@ async def answer_shell_account_target(tom: User, applet: AppletFull, session: As
activity_id=applet.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
),
client=ClientMeta(app_id=f"{uuid.uuid4()}", app_version="1.1", width=984, height=623),
@@ -238,8 +238,8 @@ async def answer_shell_account_target(tom: User, applet: AppletFull, session: As
source_subject_tag="Child",
source_nickname=shell_account.nickname,
source_secret_user_id=shell_account.secret_user_id,
- start_datetime=datetime.datetime.utcnow(),
- end_datetime=datetime.datetime.utcnow(),
+ start_datetime=datetime.datetime.now(datetime.UTC),
+ end_datetime=datetime.datetime.now(datetime.UTC),
)
@@ -256,8 +256,8 @@ async def tom_answer_on_reviewable_applet(
activity_id=applet_with_reviewable_activity.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet_with_reviewable_activity.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
),
client=ClientMeta(app_id=f"{uuid.uuid4()}", app_version="1.1", width=984, height=623),
@@ -277,8 +277,8 @@ async def lucy_answer(session: AsyncSession, lucy: User, applet: AppletFull) ->
activity_id=applet.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(lucy.id),
),
client=ClientMeta(app_id=f"{uuid.uuid4()}", app_version="1.1", width=984, height=623),
@@ -299,8 +299,8 @@ async def tom_answer_activity_flow(session: AsyncSession, tom: User, applet_with
activity_id=applet_with_flow.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet_with_flow.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
identifier="encrypted_identifier",
),
@@ -325,8 +325,8 @@ async def tom_answer_activity_flow_incomplete(
activity_id=applet_with_flow.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet_with_flow.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
identifier="encrypted_identifier",
),
@@ -344,8 +344,8 @@ def applet_with_flow_answer_create(applet_with_flow: AppletFull) -> list[AppletA
client=ClientMeta(app_id=f"{uuid.uuid4()}", app_version="1.1", width=984, height=623),
)
answer_item_data = dict(
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(uuid.uuid4()),
)
answers = [
@@ -429,8 +429,8 @@ async def tom_answer_activity_no_flow(session: AsyncSession, tom: User, applet_w
activity_id=applet_with_flow.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet_with_flow.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
),
client=ClientMeta(app_id=f"{uuid.uuid4()}", app_version="1.1", width=984, height=623),
@@ -566,8 +566,8 @@ async def tom_answer_activity_flow_not_completed(
activity_id=applet_with_flow.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet_with_flow.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
identifier="encrypted_identifier",
),
@@ -594,8 +594,8 @@ async def applet__with_deleted_activities_and_answers(
activity_id=activity.id,
answer=ItemAnswerCreate(
item_ids=[activity.items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
identifier="encrypted_identifier",
),
@@ -627,8 +627,8 @@ async def applet__with_deleted_and_order(
is_flow_completed=True,
answer=ItemAnswerCreate(
item_ids=[activity.items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
identifier="encrypted_identifier",
),
@@ -763,7 +763,7 @@ async def test_answer_activity_answer_dates_for_respondent(
self.review_activities_url.format(applet_id=str(answer_with_alert_create.applet_id)),
dict(
targetSubjectId=tom_applet_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
assert response.status_code == http.HTTPStatus.OK, response.json()
@@ -1518,7 +1518,7 @@ async def test_answered_applet_activities_1(
self.review_activities_url.format(applet_id=str(tom_answer.applet_id)),
dict(
targetSubjectId=tom_applet_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
@@ -1697,7 +1697,7 @@ async def test_applet_assessment_create(
)
)
assert response.status_code == http.HTTPStatus.OK
- assessment = response.json()["result"]
+ assessment: dict = response.json()["result"]
assert assessment["answer"] == assessment_create.answer
assert assessment["reviewerPublicKey"] == assessment_create.reviewer_public_key
assert assessment["itemIds"] == [str(i) for i in assessment_create.item_ids]
@@ -1749,7 +1749,7 @@ async def test_applet_activities(self, client: TestClient, tom: User, answer: An
self.review_activities_url.format(applet_id=str(answer.applet_id)),
dict(
targetSubjectId=tom_applet_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
@@ -1928,7 +1928,7 @@ async def test_get_activity_identifiers(
assert response.status_code == http.HTTPStatus.OK
assert response.json()["count"] == 0
- created_at = datetime.datetime.utcnow()
+ created_at = datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
data = answer_create.copy(deep=True)
data.created_at = created_at
@@ -2236,7 +2236,7 @@ async def test_check_existence_answer_exists(self, client: TestClient, tom: User
"column,value",
(
("activity_id", "00000000-0000-0000-0000-000000000000_99"),
- ("created_at", datetime.datetime.utcnow().timestamp() * 1000),
+ ("created_at", datetime.datetime.now(datetime.UTC).timestamp() * 1000),
),
)
async def test_check_existence_answer_does_not_exist(
@@ -2415,8 +2415,8 @@ async def test_summary_activities_submitted_date_with_answers(
activity_id=applet_with_reviewable_activity.activities[0].id,
answer=ItemAnswerCreate(
item_ids=[applet_with_reviewable_activity.activities[0].items[0].id],
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC),
user_public_key=str(tom.id),
),
client=ClientMeta(app_id=f"{uuid.uuid4()}", app_version="1.1", width=984, height=623),
@@ -2577,7 +2577,7 @@ async def test_review_flows_one_answer(
url,
dict(
targetSubjectId=tom_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
assert response.status_code == 200
@@ -2612,7 +2612,7 @@ async def test_review_flows_one_answer_incomplete_submission(
url,
dict(
targetSubjectId=tom_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
assert response.status_code == 200
@@ -2644,7 +2644,7 @@ async def test_review_flows_multiple_answers(
url,
dict(
targetSubjectId=tom_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
assert response.status_code == 200
@@ -3045,7 +3045,7 @@ async def test_review_flows_one_answer_without_target_subject_id(
response = await client.get(
url,
dict(
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
assert response.status_code == 422
diff --git a/src/apps/answers/tests/test_answers_arbitrary.py b/src/apps/answers/tests/test_answers_arbitrary.py
index 623aa6b4e7e..7527ec1e5ee 100644
--- a/src/apps/answers/tests/test_answers_arbitrary.py
+++ b/src/apps/answers/tests/test_answers_arbitrary.py
@@ -171,7 +171,7 @@ async def test_answer_activity_items_create_for_respondent(
self.review_activities_url.format(applet_id=str(answer_with_alert_create.applet_id)),
dict(
targetSubjectId=subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
@@ -347,7 +347,7 @@ async def test_answered_applet_activities(
self.review_activities_url.format(applet_id=str(answer_create.applet_id)),
dict(
targetSubjectId=tom_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
@@ -372,7 +372,7 @@ async def test_answered_applet_activities(
self.review_activities_url.format(applet_id=str(answer_create.applet_id)),
dict(
targetSubjectId=tom_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
@@ -467,7 +467,7 @@ async def test_applet_assessment_create(
)
)
assert response.status_code == http.HTTPStatus.OK
- assessment = response.json()["result"]
+ assessment: dict = response.json()["result"]
assert assessment["answer"] == assessment_arbitrary_create.answer
assert assessment["reviewerPublicKey"] == assessment_arbitrary_create.reviewer_public_key
assert assessment["itemIds"] == [str(i) for i in assessment_arbitrary_create.item_ids]
@@ -512,7 +512,7 @@ async def test_applet_activities(
self.review_activities_url.format(applet_id=str(answer_arbitrary.applet_id)),
dict(
targetSubjectId=tom_applet_subject.id,
- createdDate=datetime.datetime.utcnow().date(),
+ createdDate=datetime.datetime.now(datetime.UTC).date(),
),
)
@@ -665,7 +665,7 @@ async def test_get_identifiers(
assert response.status_code == http.HTTPStatus.OK
assert response.json()["count"] == 0
- created_at = datetime.datetime.utcnow()
+ created_at = datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
data = answer_create.copy(deep=True)
data.created_at = created_at
@@ -852,7 +852,7 @@ async def test_check_existance_answer_exists(
"column,value",
(
("activity_id", "00000000-0000-0000-0000-000000000000_99"),
- ("created_at", datetime.datetime.utcnow().timestamp() * 1000),
+ ("created_at", datetime.datetime.now(datetime.UTC).timestamp() * 1000),
),
)
async def test_check_existance_answer_does_not_exist(
@@ -863,8 +863,8 @@ async def test_check_existance_answer_does_not_exist(
"applet_id": str(answer_arbitrary.applet_id),
"activity_id": answer_arbitrary.activity_history_id.split("_")[0],
"created_at": answer_arbitrary.created_at.timestamp(),
+ column: value,
}
- data[column] = value
resp = await arbitrary_client.post(self.check_existence_url, data=data)
assert resp.status_code == http.HTTPStatus.OK
assert not resp.json()["result"]["exists"]
diff --git a/src/apps/applets/commands/applet_ema.py b/src/apps/applets/commands/applet_ema.py
index 0595abcb7f6..f14072bf799 100644
--- a/src/apps/applets/commands/applet_ema.py
+++ b/src/apps/applets/commands/applet_ema.py
@@ -128,7 +128,7 @@ class ActivityEventRawRow(RawRow):
def is_last_day_of_month(date: datetime.date):
mdays = calendar.mdays.copy() # type: ignore[attr-defined]
if calendar.isleap(date.year):
- mdays[calendar.February] += 1 # type: ignore[attr-defined]
+ mdays[calendar.FEBRUARY] += 1
return date.day == mdays[date.month]
@@ -210,7 +210,7 @@ async def _export_flows(applet_id: uuid.UUID, path_prefix: str):
@app.command(
short_help=f'Export applet "{APPLET_NAME or "NOT CONFIGURED"}"({APPLET_ID or "NOT CONFIGURED"})'
- f' flow data as csv file'
+ f" flow data as csv file"
)
@coro
async def export_flows(
diff --git a/src/apps/authentication/crud.py b/src/apps/authentication/crud.py
index 9ccd8115f47..33058e77b30 100644
--- a/src/apps/authentication/crud.py
+++ b/src/apps/authentication/crud.py
@@ -13,7 +13,7 @@ async def create(self, token: InternalToken, type_: TokenPurpose):
TokenBlacklistSchema(
jti=token.payload.jti,
user_id=token.payload.sub,
- exp=datetime.datetime.utcfromtimestamp(token.payload.exp),
+ exp=datetime.datetime.fromtimestamp(token.payload.exp, datetime.UTC).replace(tzinfo=None),
type=type_,
rjti=token.payload.rjti,
)
diff --git a/src/apps/authentication/deps.py b/src/apps/authentication/deps.py
index 717aa9cf597..c5d7f8b4f29 100644
--- a/src/apps/authentication/deps.py
+++ b/src/apps/authentication/deps.py
@@ -1,4 +1,4 @@
-from datetime import datetime
+from datetime import datetime, timezone
import jwt
from fastapi import Depends, HTTPException, status
@@ -44,7 +44,7 @@ async def get_current_user_for_ws(websocket: WebSocket, session=Depends(get_sess
)
token_data = TokenPayload(**payload)
- if datetime.utcfromtimestamp(token_data.exp) < datetime.utcnow():
+ if datetime.fromtimestamp(token_data.exp, timezone.utc) < datetime.now(timezone.utc):
raise AuthenticationError
except (jwt.PyJWTError, ValidationError):
raise AuthenticationError
@@ -75,7 +75,7 @@ async def _get_current_token(
token_payload = TokenPayload(**payload)
- if datetime.utcfromtimestamp(token_payload.exp) < datetime.utcnow():
+ if datetime.fromtimestamp(token_payload.exp, timezone.utc) < datetime.now(timezone.utc):
raise AuthenticationError
except (jwt.PyJWTError, ValidationError):
raise AuthenticationError
diff --git a/src/apps/authentication/services/core.py b/src/apps/authentication/services/core.py
index 952100bdaff..b4c2f5f929c 100644
--- a/src/apps/authentication/services/core.py
+++ b/src/apps/authentication/services/core.py
@@ -14,8 +14,8 @@ async def is_revoked(self, token: InternalToken) -> bool:
return await TokenBlacklistCRUD(self.session).exists(token)
async def revoke(self, token: InternalToken, type_: TokenPurpose) -> None:
- now = datetime.datetime.utcnow()
- ttl = token.payload.exp - int(now.replace(tzinfo=datetime.timezone.utc).timestamp())
+ now = datetime.datetime.now(datetime.UTC)
+ ttl = token.payload.exp - int(now.timestamp())
if ttl > 1:
revoked = await self.is_revoked(token)
if not revoked:
diff --git a/src/apps/authentication/services/security.py b/src/apps/authentication/services/security.py
index cdf3416b379..d6eb1162771 100644
--- a/src/apps/authentication/services/security.py
+++ b/src/apps/authentication/services/security.py
@@ -23,7 +23,7 @@ def __init__(self, session) -> None:
def create_access_token(data: dict) -> str:
to_encode = data.copy()
expires_delta = timedelta(minutes=settings.authentication.access_token.expiration)
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
to_encode.setdefault(JWTClaim.exp, expire)
to_encode.setdefault(JWTClaim.jti, str(uuid.uuid4()))
encoded_jwt = jwt.encode(
@@ -37,7 +37,7 @@ def create_access_token(data: dict) -> str:
def create_refresh_token(data: dict) -> str:
to_encode = data.copy()
expires_delta = timedelta(minutes=settings.authentication.refresh_token.expiration)
- expire = datetime.utcnow() + expires_delta
+ expire = datetime.now(timezone.utc) + expires_delta
to_encode.setdefault(JWTClaim.exp, expire)
to_encode.setdefault(JWTClaim.jti, str(uuid.uuid4()))
encoded_jwt = jwt.encode(
@@ -68,14 +68,14 @@ def _get_refresh_token_by_access(self, token: InternalToken) -> InternalToken |
if not token.payload.rjti:
return None
- access_exp = datetime.utcfromtimestamp(token.payload.exp)
+ access_exp = datetime.fromtimestamp(token.payload.exp, timezone.utc)
refresh_expires_delta = timedelta(minutes=settings.authentication.refresh_token.expiration)
access_expires_delta = timedelta(minutes=settings.authentication.access_token.expiration)
expire = access_exp - access_expires_delta + refresh_expires_delta
refresh_token = InternalToken(
payload=TokenPayload(
sub=token.payload.sub,
- exp=expire.replace(tzinfo=timezone.utc).timestamp(),
+ exp=int(expire.timestamp()),
jti=token.payload.rjti,
)
)
diff --git a/src/apps/file/services.py b/src/apps/file/services.py
index b175aa00d3d..e758480a5b4 100644
--- a/src/apps/file/services.py
+++ b/src/apps/file/services.py
@@ -212,7 +212,7 @@ def raise_for_access(email: str):
@staticmethod
def need_to_rotate(first_file_name: str) -> bool:
- now_ts = datetime.datetime.utcnow()
+ now_ts = datetime.datetime.now(datetime.UTC)
file_ts_part = first_file_name.split()[-1:]
if not file_ts_part:
return False
diff --git a/src/apps/folders/crud.py b/src/apps/folders/crud.py
index 0892c61e0e7..2f2febfd549 100644
--- a/src/apps/folders/crud.py
+++ b/src/apps/folders/crud.py
@@ -102,7 +102,7 @@ async def pin_applet(self, folder_id: uuid.UUID, applet_id: uuid.UUID):
query: Query = update(FolderAppletSchema)
query = query.where(FolderAppletSchema.folder_id == folder_id)
query = query.where(FolderAppletSchema.applet_id == applet_id)
- query = query.values(pinned_at=datetime.datetime.utcnow())
+ query = query.values(pinned_at=datetime.datetime.now(datetime.UTC).replace(tzinfo=None))
await self._execute(query)
diff --git a/src/apps/integrations/loris/service/loris.py b/src/apps/integrations/loris/service/loris.py
index e8829757b02..4f021088c61 100644
--- a/src/apps/integrations/loris/service/loris.py
+++ b/src/apps/integrations/loris/service/loris.py
@@ -197,7 +197,7 @@ async def integration(self, users_and_visits) -> None:
headers, candidate_id, filtered_answers, activities_ids, users_and_visits[user]
)
- logger.info(f"Successfully send data for user: {user}," f" with loris id: {candidate_id}")
+ logger.info(f"Successfully send data for user: {user}, with loris id: {candidate_id}")
await self._create_integration_alerts(self.applet_id, message=LorisIntegrationAlertMessages.SUCCESS.value)
logger.info("All finished")
@@ -644,7 +644,7 @@ async def _add_instrument_to_loris(
else:
logger.info(f"Failed request in {duration:.1f} seconds.")
error_message = await resp.text()
- logger.info(f"response is: " f"{error_message}\nstatus is: {resp.status}")
+ logger.info(f"response is: {error_message}\nstatus is: {resp.status}")
await self._create_integration_alerts(
self.applet_id, message=LorisIntegrationAlertMessages.LORIS_SERVER_ERROR.value
)
@@ -696,7 +696,7 @@ async def _add_instrument_data_to_loris(
else:
logger.info(f"Failed request in {duration:.1f} seconds.")
error_message = await resp.text()
- logger.info(f"response is: " f"{error_message}\nstatus is: {resp.status}")
+ logger.info(f"response is: {error_message}\nstatus is: {resp.status}")
await self._create_integration_alerts(
self.applet_id, message=LorisIntegrationAlertMessages.LORIS_SERVER_ERROR.value
)
diff --git a/src/apps/invitations/domain.py b/src/apps/invitations/domain.py
index 17ffab9d7e4..24b092c19f9 100644
--- a/src/apps/invitations/domain.py
+++ b/src/apps/invitations/domain.py
@@ -305,13 +305,13 @@ class _InvitationResponse(PublicModel):
description="This field represents the specific invitation id",
)
applet_id: uuid.UUID = Field(
- description="This field represents the specific applet id " "for invitation",
+ description="This field represents the specific applet id for invitation",
)
applet_name: str = Field(
- description="This field represents the specific applet name " "for invitation",
+ description="This field represents the specific applet name for invitation",
)
key: uuid.UUID = Field(
- description="This field represents the universally unique " "identifiers for invitation",
+ description="This field represents the universally unique identifiers for invitation",
)
status: InvitationStatus = Field(
description="This field represents the status for invitation",
@@ -324,7 +324,7 @@ class _InvitationResponse(PublicModel):
)
user_id: uuid.UUID | None = Field(
None,
- description="This field respresents registered user or not. " "Used for tests",
+ description="This field respresents registered user or not. Used for tests",
)
tag: str | None = Field(None, description="This field represents subject tag")
diff --git a/src/apps/invitations/test_invite.py b/src/apps/invitations/test_invite.py
index 3a36de67c95..c175ddc692e 100644
--- a/src/apps/invitations/test_invite.py
+++ b/src/apps/invitations/test_invite.py
@@ -816,7 +816,7 @@ async def test_send_incorrect_role_to_invite_managers(
data,
)
assert resp.status_code == http.HTTPStatus.UNPROCESSABLE_ENTITY
- emsg = "value is not a valid enumeration member; " "permitted: 'manager', 'coordinator', 'editor'"
+ emsg = "value is not a valid enumeration member; permitted: 'manager', 'coordinator', 'editor'"
result = resp.json()["result"]
assert len(result) == 1
assert result[0]["message"] == emsg
diff --git a/src/apps/jsonld_converter/service/document/base.py b/src/apps/jsonld_converter/service/document/base.py
index 38a05b581ad..ac928f00e7f 100644
--- a/src/apps/jsonld_converter/service/document/base.py
+++ b/src/apps/jsonld_converter/service/document/base.py
@@ -236,7 +236,7 @@ def _get_ld_properties_formatted(self, doc: dict, drop=False, key="reproschema:a
def _get_allow_list(self, doc: dict, drop=False) -> list[str]:
rules = self.attr_processor.get_attr_list(doc, "reproschema:allow", drop=drop) or []
- return [rule.get(LdKeyword.id) if isinstance(rule, dict) else rule for rule in rules]
+ return [rule.get(LdKeyword.id) if isinstance(rule, dict) else rule for rule in rules] # type: ignore
def _is_allowed(self, allow_list: list[str], keys: list[str]) -> bool:
for key in keys:
diff --git a/src/apps/jsonld_converter/service/document/report.py b/src/apps/jsonld_converter/service/document/report.py
index 83d264642db..b436cb25858 100644
--- a/src/apps/jsonld_converter/service/document/report.py
+++ b/src/apps/jsonld_converter/service/document/report.py
@@ -151,6 +151,7 @@ def _get_score_items(cls, expression: str | None) -> list[str]:
@property
def calculation_type(self) -> CalculationType:
+ assert self.ld_output_type
if self.ld_output_type == "cumulative":
return CalculationType.SUM
return CalculationType(self.ld_output_type)
diff --git a/src/apps/jsonld_converter/service/export/activity_item.py b/src/apps/jsonld_converter/service/export/activity_item.py
index a8d42b21294..7af9aab4fe5 100644
--- a/src/apps/jsonld_converter/service/export/activity_item.py
+++ b/src/apps/jsonld_converter/service/export/activity_item.py
@@ -204,7 +204,7 @@ def _build_choices_prop(self, values: SliderValues) -> list:
"schema:value": v,
}
if scores:
- choice["schema:score"] = scores[i]
+ choice["schema:score"] = scores[i] # type: ignore[assignment]
if image:
choice["schema:image"] = image
@@ -272,7 +272,7 @@ def _build_response_options_prop(self, model: ActivityItemFull) -> dict:
"schema:maxValue": row.max_label,
"schema:minValueImg": row.min_image,
"schema:maxValueImg": row.max_image,
- "choices": self._build_choices_prop(row),
+ "choices": self._build_choices_prop(row), # type: ignore[arg-type]
}
slider_options.append(option)
diff --git a/src/apps/jsonld_converter/service/export/conditional_logic.py b/src/apps/jsonld_converter/service/export/conditional_logic.py
index 15a169b450b..6c687687ecc 100644
--- a/src/apps/jsonld_converter/service/export/conditional_logic.py
+++ b/src/apps/jsonld_converter/service/export/conditional_logic.py
@@ -64,7 +64,7 @@ def export(self) -> str:
operator = self.simple_operator_map.get(type_) # type: ignore[call-overload] # noqa: E501
if isinstance(payload, OptionPayload):
try:
- val: int | str = int(payload.option_value) # TODO actualize on PR merge
+ val: int | str | float = int(payload.option_value) # TODO actualize on PR merge
except ValueError:
val = f'"{payload.option_value}"' # TODO actualize on PR merge
elif isinstance(payload, ValuePayload):
diff --git a/src/apps/schedule/commands/remove_events.py b/src/apps/schedule/commands/remove_events.py
index 2a6a3300bb5..090acb357d6 100644
--- a/src/apps/schedule/commands/remove_events.py
+++ b/src/apps/schedule/commands/remove_events.py
@@ -28,7 +28,7 @@ async def remove_events():
assessments = await get_assessments(session)
service = ScheduleService(session)
for activity in assessments:
- print(f"Applet: {activity.applet_id} " f"Activity: {activity.id}")
+ print(f"Applet: {activity.applet_id} Activity: {activity.id}")
await service.delete_by_activity_ids(activity.applet_id, [activity.id])
except Exception as ex:
print(ex)
diff --git a/src/apps/schedule/domain/schedule/base.py b/src/apps/schedule/domain/schedule/base.py
index 009ec00a325..6025c2c6e08 100644
--- a/src/apps/schedule/domain/schedule/base.py
+++ b/src/apps/schedule/domain/schedule/base.py
@@ -19,7 +19,7 @@ class BasePeriodicity(BaseModel):
end_date: date | None
selected_date: date | None = Field(
None,
- description="If type is WEEKLY, MONTHLY or ONCE," " selectedDate must be set.",
+ description="If type is WEEKLY, MONTHLY or ONCE, selectedDate must be set.",
)
@root_validator
diff --git a/src/apps/schedule/errors.py b/src/apps/schedule/errors.py
index 725dd6826f6..21e8cbbe20d 100644
--- a/src/apps/schedule/errors.py
+++ b/src/apps/schedule/errors.py
@@ -74,7 +74,7 @@ class OneTimeCompletionCaseError(FieldError):
class StartEndTimeAccessBeforeScheduleCaseError(FieldError):
- message = _("start_time, end_time, access_before_schedule " "must be set if periodicity is not ALWAYS.")
+ message = _("start_time, end_time, access_before_schedule must be set if periodicity is not ALWAYS.")
class StartEndTimeEqualError(FieldError):
diff --git a/src/apps/shared/commands/encryption.py b/src/apps/shared/commands/encryption.py
index 0ee7cbc86b1..c33e5ce6f9f 100644
--- a/src/apps/shared/commands/encryption.py
+++ b/src/apps/shared/commands/encryption.py
@@ -112,7 +112,7 @@ async def reencrypt(
print(f"Started reencrypting data in the table {table_name}")
columns = table_name_column_name_map.get(table_name, [])
if not columns:
- print("[red]" f"[bold]{table_name}[/bold] table does not have encrypted columns. Skipped[red]")
+ print(f"[red][bold]{table_name}[/bold] table does not have encrypted columns. Skipped[red]")
continue
for column in columns:
print(f"Update column {column}")
diff --git a/src/apps/shared/commands/patches/m2_4611_add_answer_subjects.py b/src/apps/shared/commands/patches/m2_4611_add_answer_subjects.py
index ec33cc8e685..c797a745e28 100644
--- a/src/apps/shared/commands/patches/m2_4611_add_answer_subjects.py
+++ b/src/apps/shared/commands/patches/m2_4611_add_answer_subjects.py
@@ -46,7 +46,7 @@ async def main(
try:
await update_answers(arb_session)
await arb_session.commit()
- print(f"Processing workspace#{i + 1} {workspace.id} " f"finished")
+ print(f"Processing workspace#{i + 1} {workspace.id} finished")
except Exception:
await arb_session.rollback()
print(f"[bold red]Error: Workspace#{i + 1} {workspace.id} processing error[/bold red]")
diff --git a/src/apps/shared/commands/patches/m2_6733_add_answer_input_subjects.py b/src/apps/shared/commands/patches/m2_6733_add_answer_input_subjects.py
index 78338aabf01..7c010da241c 100644
--- a/src/apps/shared/commands/patches/m2_6733_add_answer_input_subjects.py
+++ b/src/apps/shared/commands/patches/m2_6733_add_answer_input_subjects.py
@@ -43,8 +43,8 @@ async def main(
try:
await update_answers(arb_session)
await arb_session.commit()
- print(f"Processing workspace#{i + 1} {workspace.id} " f"finished")
+ print(f"Processing workspace#{i + 1} {workspace.id} finished")
except Exception:
await arb_session.rollback()
- print(f"[bold red]Workspace#{i + 1} {workspace.id} " f"processing error[/bold red]")
+ print(f"[bold red]Workspace#{i + 1} {workspace.id} processing error[/bold red]")
raise
diff --git a/src/apps/shared/commands/patches/m2_6879_create_deleted_respondents.py b/src/apps/shared/commands/patches/m2_6879_create_deleted_respondents.py
index 279014bd5b9..ea6589f8ff3 100644
--- a/src/apps/shared/commands/patches/m2_6879_create_deleted_respondents.py
+++ b/src/apps/shared/commands/patches/m2_6879_create_deleted_respondents.py
@@ -145,7 +145,7 @@ async def main(session: AsyncSession, *args, **kwargs):
try:
await find_and_create_missing_roles_arbitrary(session, arb_session, workspace.user_id)
await session.commit()
- print(f"Processing workspace#{i + 1} {workspace.id} " f"finished")
+ print(f"Processing workspace#{i + 1} {workspace.id} finished")
except Exception:
await session.rollback()
print(f"[bold red]Error: Workspace#{i + 1} {workspace.id} processing error[/bold red]")
diff --git a/src/apps/shared/commands/patches/m2_7203_migrate_secret_ids.py b/src/apps/shared/commands/patches/m2_7203_migrate_secret_ids.py
index 7be40abe971..adaeb4be337 100644
--- a/src/apps/shared/commands/patches/m2_7203_migrate_secret_ids.py
+++ b/src/apps/shared/commands/patches/m2_7203_migrate_secret_ids.py
@@ -16,7 +16,7 @@
from apps.subjects.db.schemas import SubjectSchema
MARKER_DELETED = "#deleted#"
-UPDATED_AT = datetime.datetime.utcnow().date()
+UPDATED_AT = datetime.datetime.now(datetime.UTC).date()
def mongoid_to_uuid(id_):
diff --git a/src/apps/shared/domain/base.py b/src/apps/shared/domain/base.py
index b01d7aeb518..20abd456fb4 100644
--- a/src/apps/shared/domain/base.py
+++ b/src/apps/shared/domain/base.py
@@ -1,9 +1,10 @@
+import datetime
import json
import re
from typing import TypeVar
from pydantic import BaseModel as PBaseModel
-from pydantic import Extra
+from pydantic import Extra, validator
__all__ = [
"InternalModel",
@@ -82,6 +83,12 @@ class BaseModel(PBaseModel):
def field_alias(cls, field_name: str):
return cls.__fields__[field_name].alias
+ @validator("*", pre=True)
+ def remove_timezone(cls, v):
+ if isinstance(v, datetime.datetime):
+ return v.replace(tzinfo=None)
+ return v
+
class InternalModel(BaseModel):
class Config:
diff --git a/src/apps/shared/domain/custom_validations.py b/src/apps/shared/domain/custom_validations.py
index ff096fe81e2..2ee9966dff7 100644
--- a/src/apps/shared/domain/custom_validations.py
+++ b/src/apps/shared/domain/custom_validations.py
@@ -122,7 +122,7 @@ def datetime_from_ms(value):
value > datetime.datetime(year=2000, month=1, day=1, tzinfo=datetime.timezone.utc).timestamp() * 1000
): # ms, assume date > 2000-01-01
value = value / 1000 # wtf, rework this
- return datetime.datetime.utcfromtimestamp(value)
+ return datetime.datetime.fromtimestamp(value, datetime.UTC)
return value
diff --git a/src/apps/shared/domain/response/errors.py b/src/apps/shared/domain/response/errors.py
index a001384123e..777bbc6ecdc 100644
--- a/src/apps/shared/domain/response/errors.py
+++ b/src/apps/shared/domain/response/errors.py
@@ -24,7 +24,7 @@ class ErrorResponseMessage(PublicModel):
class ErrorResponse(PublicModel):
"""Error response model."""
- message: str = Field(description="This field represent the objects " "with language-specific errors")
+ message: str = Field(description="This field represent the objects with language-specific errors")
type: str = Field(
description="This field represents the business-specific error type",
default=ErrorResponseType.UNDEFINED,
diff --git a/src/apps/shared/test/base.py b/src/apps/shared/test/base.py
index 20f67c174a8..a6ed7544377 100644
--- a/src/apps/shared/test/base.py
+++ b/src/apps/shared/test/base.py
@@ -49,7 +49,7 @@ async def load_data(self, relative_path: str):
values = ",".join(map(_str_caster, datum["fields"].values()))
query = text(
f"""
- insert into "{datum['table']}"({columns}) values ({values})
+ insert into "{datum["table"]}"({columns}) values ({values})
"""
)
await session.execute(query)
diff --git a/src/apps/subjects/crud/subject.py b/src/apps/subjects/crud/subject.py
index 57971b667aa..e7d11a17132 100644
--- a/src/apps/subjects/crud/subject.py
+++ b/src/apps/subjects/crud/subject.py
@@ -1,5 +1,5 @@
import uuid
-from datetime import datetime
+from datetime import datetime, timezone
from asyncpg import UniqueViolationError
from sqlalchemy import and_, delete, func, or_, select, update
@@ -168,8 +168,8 @@ async def upsert(self, schema: SubjectCreate) -> SubjectSchema | None:
index_elements=[SubjectSchema.user_id, SubjectSchema.applet_id],
set_={
**values,
- "created_at": datetime.utcnow(),
- "updated_at": datetime.utcnow(),
+ "created_at": datetime.now(timezone.utc).replace(tzinfo=None),
+ "updated_at": datetime.now(timezone.utc).replace(tzinfo=None),
},
where=SubjectSchema.soft_exists(exists=False),
).returning(SubjectSchema.id)
diff --git a/src/apps/users/commands/token.py b/src/apps/users/commands/token.py
index 4b86aaebbf7..db6f6429f0c 100644
--- a/src/apps/users/commands/token.py
+++ b/src/apps/users/commands/token.py
@@ -21,7 +21,7 @@ async def generate(
if ttl:
expires_delta = datetime.timedelta(seconds=ttl)
- expire = datetime.datetime.utcnow() + expires_delta
+ expire = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) + expires_delta
payload[JWTClaim.exp] = expire
access_token = AuthenticationService.create_access_token(payload)
diff --git a/src/apps/users/cruds/user.py b/src/apps/users/cruds/user.py
index a7e7ee958b6..4d5e91c4f0a 100644
--- a/src/apps/users/cruds/user.py
+++ b/src/apps/users/cruds/user.py
@@ -90,7 +90,7 @@ async def change_password(self, user: User, update_schema: UserChangePassword) -
async def update_last_seen_by_id(self, id_: uuid.UUID) -> None:
query = update(UserSchema)
query = query.where(UserSchema.id == id_)
- query = query.values(last_seen_at=datetime.datetime.utcnow())
+ query = query.values(last_seen_at=datetime.datetime.now(datetime.UTC).replace(tzinfo=None))
await self._execute(query)
async def exist_by_id(self, id_: uuid.UUID) -> bool:
diff --git a/src/apps/users/cruds/user_device.py b/src/apps/users/cruds/user_device.py
index 8898de7f73f..1e8baf3940c 100644
--- a/src/apps/users/cruds/user_device.py
+++ b/src/apps/users/cruds/user_device.py
@@ -27,7 +27,7 @@ async def upsert(self, user_id: uuid.UUID, device_id: str, **data):
constraint=UserDeviceSchema.uq_constraint,
set_={
**values,
- "updated_at": datetime.datetime.utcnow(),
+ "updated_at": datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
},
)
.returning(UserDeviceSchema)
diff --git a/src/apps/users/db/schemas.py b/src/apps/users/db/schemas.py
index ffd4869988d..403cbef874f 100644
--- a/src/apps/users/db/schemas.py
+++ b/src/apps/users/db/schemas.py
@@ -1,4 +1,4 @@
-from datetime import datetime
+from datetime import datetime, timezone
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, String, Text, Unicode, UniqueConstraint
from sqlalchemy_utils import StringEncryptedType
@@ -15,7 +15,7 @@ class UserSchema(Base):
first_name = Column(StringEncryptedType(Unicode, get_key))
last_name = Column(StringEncryptedType(Unicode, get_key))
hashed_password = Column(String(length=100))
- last_seen_at = Column(DateTime(), default=datetime.utcnow)
+ last_seen_at = Column(DateTime(), default=lambda: datetime.now(timezone.utc).replace(tzinfo=None))
is_super_admin = Column(Boolean(), default=False, server_default="false")
is_anonymous_respondent = Column(Boolean(), default=False, server_default="false")
is_legacy_deleted_respondent = Column(Boolean(), default=False, server_default="false")
diff --git a/src/apps/users/tasks.py b/src/apps/users/tasks.py
index 7fe5515cf4b..fd408dd86a3 100644
--- a/src/apps/users/tasks.py
+++ b/src/apps/users/tasks.py
@@ -81,7 +81,7 @@ async def reencrypt_answers(
page += 1
except Exception as e:
- msg = f"Reencryption {user_id}: cannot process applet " f"{applet.applet_id}, skip"
+ msg = f"Reencryption {user_id}: cannot process applet {applet.applet_id}, skip"
logger.error(msg)
logger.exception(str(e))
async with default_session_maker() as session:
diff --git a/src/apps/users/tests/test_password.py b/src/apps/users/tests/test_password.py
index ee881b0c9f2..09a1d0d9ed5 100644
--- a/src/apps/users/tests/test_password.py
+++ b/src/apps/users/tests/test_password.py
@@ -29,7 +29,7 @@ def cache_entry(user: UserCreate):
instance=PasswordRecoveryInfoFactory.build(
email=user.email,
),
- created_at=datetime.datetime.utcnow(),
+ created_at=datetime.datetime.now(datetime.UTC),
)
diff --git a/src/apps/users/tests/test_reencrypt_user_answers.py b/src/apps/users/tests/test_reencrypt_user_answers.py
index 9b526398fef..016aff41b7a 100644
--- a/src/apps/users/tests/test_reencrypt_user_answers.py
+++ b/src/apps/users/tests/test_reencrypt_user_answers.py
@@ -44,8 +44,8 @@ def job_model(user: User) -> Job:
creator_id=user.id,
status=JobStatus.in_progress,
id=uuid.uuid4(),
- created_at=datetime.datetime.utcnow(),
- updated_at=datetime.datetime.utcnow(),
+ created_at=datetime.datetime.now(datetime.UTC),
+ updated_at=datetime.datetime.now(datetime.UTC),
)
@@ -89,8 +89,8 @@ def answer_item_create(
item_ids=[applet.activities[0].items[0].id],
identifier=None,
scheduled_time=None,
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow() + datetime.timedelta(seconds=1),
+ start_time=datetime.datetime.now(datetime.UTC),
+ end_time=datetime.datetime.now(datetime.UTC) + datetime.timedelta(seconds=1),
user_public_key=str(public_key),
)
@@ -109,7 +109,7 @@ async def answer(
submit_id=uuid.uuid4(),
activity_id=applet.activities[0].id,
answer=answer_item_create,
- created_at=datetime.datetime.utcnow(),
+ created_at=datetime.datetime.now(datetime.UTC),
client=client_meta,
consent_to_share=False,
)
@@ -132,7 +132,7 @@ async def answer_second(
submit_id=uuid.uuid4(),
activity_id=applet.activities[0].id,
answer=answer_item_create,
- created_at=datetime.datetime.utcnow(),
+ created_at=datetime.datetime.now(datetime.UTC),
client=client_meta,
consent_to_share=False,
)
@@ -156,7 +156,7 @@ async def answer_arbitrary(
submit_id=uuid.uuid4(),
activity_id=applet.activities[0].id,
answer=answer_item_create,
- created_at=datetime.datetime.utcnow(),
+ created_at=datetime.datetime.now(datetime.UTC),
client=client_meta,
consent_to_share=False,
)
@@ -294,7 +294,7 @@ async def test_reencrypt_answers_exception_during_reencrypt_no_retries(
spy = mocker.spy(JobService, "change_status")
task = await reencrypt_answers.kiq(user.id, user.email_encrypted, user_create.password, "new-pass", retries=0)
await task.wait_result()
- err_msg = f"Reencryption {user_id}: cannot process applet " f"{applet.id}, skip"
+ err_msg = f"Reencryption {user_id}: cannot process applet {applet.id}, skip"
spy.assert_awaited_once_with(ANY, job_model.id, JobStatus.error, dict(errors=[err_msg, "ERROR"]))
answer_after = (await AnswerItemsCRUD(session).get_by_answer_and_activity(answer_id, [act_id_version]))[0].answer
assert answer_before == answer_after
diff --git a/src/apps/workspaces/crud/user_applet_access.py b/src/apps/workspaces/crud/user_applet_access.py
index 33049c775b8..b2f46c1c970 100644
--- a/src/apps/workspaces/crud/user_applet_access.py
+++ b/src/apps/workspaces/crud/user_applet_access.py
@@ -1,5 +1,5 @@
import uuid
-from datetime import datetime
+from datetime import datetime, timezone
from typing import Tuple
from asyncpg.exceptions import UniqueViolationError
@@ -217,8 +217,8 @@ async def upsert_user_applet_access(self, schema: UserAppletAccessSchema, where=
"applet_id": stmt.excluded.applet_id,
"role": stmt.excluded.role,
"is_deleted": stmt.excluded.is_deleted,
- "created_at": datetime.utcnow(),
- "updated_at": datetime.utcnow(),
+ "created_at": datetime.now(timezone.utc).replace(tzinfo=None),
+ "updated_at": datetime.now(timezone.utc).replace(tzinfo=None),
"meta": stmt.excluded.meta,
"nickname": stmt.excluded.nickname,
"title": stmt.excluded.title,
@@ -228,7 +228,7 @@ async def upsert_user_applet_access(self, schema: UserAppletAccessSchema, where=
result = list(await self._execute(stmt))
if not result:
- raise UniqueViolationError("duplicate key value violates unique" ' constraint "unique_user_applet_role"')
+ raise UniqueViolationError('duplicate key value violates unique constraint "unique_user_applet_role"')
return result
diff --git a/src/apps/workspaces/domain/workspace.py b/src/apps/workspaces/domain/workspace.py
index 7abd125e6ee..213ffee2bf6 100644
--- a/src/apps/workspaces/domain/workspace.py
+++ b/src/apps/workspaces/domain/workspace.py
@@ -376,7 +376,7 @@ def validate_storage_settings(cls, values):
required = ["storage_url", "storage_bucket", "storage_access_key"]
if required and not all((values[itm] is not None) for itm in required):
- raise ValueError(f"{', '.join(required)} are required " f"for {storage_type} storage")
+ raise ValueError(f"{', '.join(required)} are required for {storage_type} storage")
return values
diff --git a/src/apps/workspaces/errors.py b/src/apps/workspaces/errors.py
index bc350f7ea03..3ba3f245fd5 100644
--- a/src/apps/workspaces/errors.py
+++ b/src/apps/workspaces/errors.py
@@ -87,7 +87,7 @@ class AppletInviteAccessDenied(AccessDeniedError):
class AppletSetScheduleAccessDenied(AccessDeniedError):
- message = _("Access denied to manipulate with " "schedules and notifications of the applet.")
+ message = _("Access denied to manipulate with schedules and notifications of the applet.")
class TransferOwnershipAccessDenied(AccessDeniedError):
diff --git a/src/apps/workspaces/service/storage.py b/src/apps/workspaces/service/storage.py
index f8c0419fc1a..015dbe033de 100644
--- a/src/apps/workspaces/service/storage.py
+++ b/src/apps/workspaces/service/storage.py
@@ -16,7 +16,7 @@ def __init__(
self.client = None
def _get_full_path(self, applet_id: uuid.UUID, activity_id: uuid.UUID) -> str:
- return f"{self.workspace_id}/" f"{applet_id}/" f"{activity_id}/" f"{self._get_filename()}"
+ return f"{self.workspace_id}/{applet_id}/{activity_id}/{self._get_filename()}"
def _get_filename(self) -> str:
return "filename"
diff --git a/src/apps/workspaces/tests/test_workspaces.py b/src/apps/workspaces/tests/test_workspaces.py
index f117e8b27ee..8217df504c7 100644
--- a/src/apps/workspaces/tests/test_workspaces.py
+++ b/src/apps/workspaces/tests/test_workspaces.py
@@ -133,10 +133,10 @@ async def tom_answer_applet_one(session, tom: User, applet_one: AppletFull):
activity_id=activity.id,
answer=ItemAnswerCreate(
item_ids=items_ids,
- start_time=datetime.datetime.utcnow(),
- end_time=datetime.datetime.utcnow(),
+ start_time=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
+ end_time=datetime.datetime.now(datetime.UTC).replace(tzinfo=None),
),
- client=ClientMeta(app_id="web", app_version="1.1.0", width="800", height="600"),
+ client=ClientMeta(app_id="web", app_version="1.1.0", width=800, height=600),
target_subject_id=subject.id,
source_subject_id=subject.id,
consent_to_share=False,
@@ -214,7 +214,7 @@ class TestWorkspaces(BaseTest):
workspace_respondents_pin = "/workspaces/{owner_id}/respondents/{user_id}/pin"
workspace_subject_pin = "/workspaces/{owner_id}/subjects/{subject_id}/pin"
workspace_managers_pin = "/workspaces/{owner_id}/managers/{user_id}/pin"
- workspace_get_applet_respondent = "/workspaces/{owner_id}" "/applets/{applet_id}" "/respondents/{respondent_id}"
+ workspace_get_applet_respondent = "/workspaces/{owner_id}/applets/{applet_id}/respondents/{respondent_id}"
@pytest.mark.usefixtures("applet_three")
async def test_user_workspace_list(self, client, lucy):
@@ -1477,7 +1477,7 @@ async def test_user_last_activity_workspace_respondent_retrieve(
assert response.status_code == 200, response.json()
result = response.json()["result"]
date_answer = datetime.datetime.fromisoformat(result["lastSeen"])
- date_now = datetime.datetime.utcnow()
+ date_now = datetime.datetime.now(datetime.UTC)
assert date_now.day == date_answer.day
assert date_now.month == date_answer.month
assert date_now.year == date_answer.year
diff --git a/src/config/database.py b/src/config/database.py
index b4e15902958..32b98017b13 100644
--- a/src/config/database.py
+++ b/src/config/database.py
@@ -11,4 +11,4 @@ class DatabaseSettings(BaseModel):
@property
def url(self) -> str:
- return f"postgresql+asyncpg://{self.user}:{self.password}" f"@{self.host}:{self.port}/{self.db}"
+ return f"postgresql+asyncpg://{self.user}:{self.password}@{self.host}:{self.port}/{self.db}"
diff --git a/src/config/task.py b/src/config/task.py
index 10a617a6ea3..ae55b39dff2 100644
--- a/src/config/task.py
+++ b/src/config/task.py
@@ -14,6 +14,6 @@ class AudioFileConvert(BaseModel):
class ImageConvert(BaseModel):
- command: str = "convert -strip -interlace JPEG -sampling-factor 4:2:0 " "-quality 85 -colorspace RGB {fin} {fout}"
+ command: str = "convert -strip -interlace JPEG -sampling-factor 4:2:0 -quality 85 -colorspace RGB {fin} {fout}"
subprocess_timeout: int = 20 # sec
task_wait_timeout: int = 10 # sec
diff --git a/src/infrastructure/app.py b/src/infrastructure/app.py
index b38807cace0..4b4dc629c61 100644
--- a/src/infrastructure/app.py
+++ b/src/infrastructure/app.py
@@ -93,7 +93,7 @@
def create_app():
# Create base FastAPI application
app = FastAPI(
- description=f"Commit id: {settings.commit_id}" f"
Version: {settings.version}",
+ description=f"Commit id: {settings.commit_id}
Version: {settings.version}",
debug=settings.debug,
)
diff --git a/src/infrastructure/cache/services.py b/src/infrastructure/cache/services.py
index f60fc13d6ff..f80890b8379 100644
--- a/src/infrastructure/cache/services.py
+++ b/src/infrastructure/cache/services.py
@@ -1,6 +1,6 @@
import json
from abc import ABC, abstractmethod
-from datetime import datetime
+from datetime import datetime, timezone
from typing import Generic
from config import settings
@@ -84,7 +84,10 @@ async def set(
instance: _InputObject,
ttl: int | None = None,
) -> CacheEntry[_InputObject]:
- enhanced_cache_entry: CacheEntry[_InputObject] = CacheEntry(instance=instance, created_at=datetime.utcnow())
+ enhanced_cache_entry: CacheEntry[_InputObject] = CacheEntry(
+ instance=instance,
+ created_at=datetime.now(timezone.utc),
+ )
await self.redis_client.set(
key=self._build_key(key=key),
diff --git a/src/infrastructure/database/base.py b/src/infrastructure/database/base.py
index 9257c332157..d109b15855e 100644
--- a/src/infrastructure/database/base.py
+++ b/src/infrastructure/database/base.py
@@ -1,5 +1,5 @@
import uuid
-from datetime import datetime
+from datetime import datetime, timezone
from sqlalchemy import Column, DateTime, MetaData, inspect, text
from sqlalchemy.dialects.postgresql import UUID
@@ -36,13 +36,13 @@ class Base(SoftDeletable, _Base): # type: ignore
)
created_at = Column(
DateTime(),
- default=datetime.utcnow,
+ default=lambda: datetime.now(timezone.utc).replace(tzinfo=None),
server_default=text("timezone('utc', now())"),
)
updated_at = Column(
DateTime(),
- default=datetime.utcnow,
- onupdate=datetime.utcnow,
+ default=lambda: datetime.now(timezone.utc).replace(tzinfo=None),
+ onupdate=lambda: datetime.now(timezone.utc).replace(tzinfo=None),
server_default=text("timezone('utc', now())"),
server_onupdate=text("timezone('utc', now())"),
)
diff --git a/src/infrastructure/database/crud.py b/src/infrastructure/database/crud.py
index 06c41d29291..5460b9d4a09 100644
--- a/src/infrastructure/database/crud.py
+++ b/src/infrastructure/database/crud.py
@@ -109,7 +109,7 @@ async def count(self, **filters: Any) -> int:
if not isinstance(value, int):
raise Exception(
- "For some reason count function returned not an integer." f"Value: {value}",
+ f"For some reason count function returned not an integer.Value: {value}",
)
return value
diff --git a/src/infrastructure/utility/cdn_arbitrary.py b/src/infrastructure/utility/cdn_arbitrary.py
index 949df8af0bf..efe307f74d5 100644
--- a/src/infrastructure/utility/cdn_arbitrary.py
+++ b/src/infrastructure/utility/cdn_arbitrary.py
@@ -1,5 +1,5 @@
from contextlib import suppress
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, timezone
from typing import BinaryIO
import boto3
@@ -76,7 +76,7 @@ def _check_existence(self, bucket: str, key: str):
def _generate_presigned_url(self, key: str):
blob_client = self.client.get_blob_client(self.default_container_name, key)
permissions = BlobSasPermissions(read=True)
- expiration = datetime.utcnow() + timedelta(seconds=self.config.ttl_signed_urls)
+ expiration = datetime.now(timezone.utc) + timedelta(seconds=self.config.ttl_signed_urls)
sas_token = generate_blob_sas(
account_name=self.client.account_name,
container_name=self.default_container_name,
diff --git a/src/infrastructure/utility/redis_client.py b/src/infrastructure/utility/redis_client.py
index 89e3d8d0747..c06e9be95a2 100644
--- a/src/infrastructure/utility/redis_client.py
+++ b/src/infrastructure/utility/redis_client.py
@@ -14,7 +14,7 @@ class RedisCacheTest:
_storage: dict = {}
async def get(self, key: str):
- now = datetime.datetime.utcnow()
+ now = datetime.datetime.now(datetime.UTC)
value, expiry = self._storage.get(key, [None, None])
if not value or (expiry and now > expiry):
@@ -23,7 +23,7 @@ async def get(self, key: str):
return value
async def set(self, name, value, ex=None, **kwargs):
- now = datetime.datetime.utcnow()
+ now = datetime.datetime.now(datetime.UTC)
self._storage[name] = [
value,
(now + datetime.timedelta(seconds=ex)) if ex else None,
@@ -39,7 +39,7 @@ async def keys(self, pattern: str = "*") -> list[str]:
pattern = ".+"
filtered_keys = []
for key, [_, expire] in self._storage.items():
- if expire and expire < datetime.datetime.utcnow():
+ if expire and expire < datetime.datetime.now(datetime.UTC):
continue
is_match = re.match(pattern, key)
if is_match:
@@ -50,7 +50,7 @@ async def mget(self, keys) -> list[typing.Any]:
results = []
for key in keys:
result, expire = self._storage.get(key, [None, None])
- if expire > datetime.datetime.utcnow():
+ if expire > datetime.datetime.now(datetime.UTC):
results.append(result)
return results