diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1a7b0d7..89db26b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,54 +10,29 @@ on: - ".*" workflow_dispatch: -env: - PYTHON_VERSION: 3.8 - jobs: test: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: [3.8] - steps: - - name: ๐Ÿ›ซ Checkout - uses: actions/checkout@v3 - - - name: ๐Ÿ Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: ๐Ÿ›  Install Dependencies - run: | - python -m pip install --upgrade pip - python -m pip install pipenv - pipenv install --dev - - - name: ๐Ÿ”Ž Check Code Format - run: if ! pipenv run black --check .; then exit 1; fi - - - name: ๐Ÿ”Ž Check Migrations - run: pipenv run python manage.py makemigrations --check --dry-run - - # TODO: assert code coverage target. - - name: ๐Ÿงช Test Code Units - run: pipenv run pytest + uses: ocadotechnology/codeforlife-workspace/.github/workflows/test-python-code.yaml@main + with: + # Cannot be set with an env var. Value must match in the release job. + python-version: 3.8 release: concurrency: release runs-on: ubuntu-latest needs: [test] if: github.ref_name == 'main' + env: + # Value must match in the test job. + PYTHON_VERSION: 3.8 steps: - name: ๐Ÿ›ซ Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.CFL_BOT_GITHUB_TOKEN }} fetch-depth: 0 - - name: ๐Ÿ Set up Python + - name: ๐Ÿ Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@v4 with: python-version: ${{ env.PYTHON_VERSION }} @@ -67,10 +42,8 @@ jobs: python -m pip install --upgrade pip python -m pip install python-semantic-release~=7.33 - - name: โš™๏ธ Configure Git - run: | - git config --local user.name cfl-bot - git config --local user.email codeforlife-bot@ocado.com + - name: ๐Ÿค– Set up cfl-bot as Git User + uses: ocadotechnology/codeforlife-workspace/.github/actions/git/setup-bot@main - name: ๐Ÿš€ Publish Semantic Release env: diff --git a/Pipfile b/Pipfile index f4be070..f702c0e 100644 --- a/Pipfile +++ b/Pipfile @@ -17,8 +17,8 @@ importlib-metadata = "==4.13.0" # TODO: remove. needed by old portal django-formtools = "==2.2" # TODO: remove. needed by old portal django-otp = "==1.0.2" # TODO: remove. needed by old portal # https://pypi.org/user/codeforlife/ -cfl-common = "==6.41.5" # TODO: remove -codeforlife-portal = "==6.41.5" # TODO: remove +cfl-common = "==6.41.10" # TODO: remove +codeforlife-portal = "==6.41.10" # TODO: remove aimmo = "==2.11.2" # TODO: remove rapid-router = "==5.16.21" # TODO: remove phonenumbers = "==8.12.12" # TODO: remove diff --git a/Pipfile.lock b/Pipfile.lock index 460158f..e0e310f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "faa5c6a7c151ec88930b9a47b55c2a26c78f6b588f9072b4363974987c6bbe99" + "sha256": "bde2bbcff41e1dfa67036ae9cc505d55d74f65295182ca7c981d8de42e6ae512" }, "pipfile-spec": 6, "requires": { @@ -58,11 +58,11 @@ }, "cfl-common": { "hashes": [ - "sha256:87fddbf4ae8d37ee48232f15161b4c9e237f9140a309199a1b27d9e44baf2ffe", - "sha256:a43e630a699160faf7a0a6af46ed14f464aa4420e1fe2db02842db4347544436" + "sha256:2a223a56ae479a1f2ae9c3458f769f67d0532d91b355a89942e2c69bb0cd249d", + "sha256:b3479a1da60179d448e19eaf3a229aad3d08df81ca8d1f1cbbcb2ec09f995e71" ], "index": "pypi", - "version": "==6.41.5" + "version": "==6.41.10" }, "charset-normalizer": { "hashes": [ @@ -170,11 +170,11 @@ }, "codeforlife-portal": { "hashes": [ - "sha256:03c351ff447d46893a79e498f72539d3c62af0ad2c19578904b6415f1c514c4a", - "sha256:ef91c3cbaa48682e72ddbdeaf3dc25f4505bfb50aeb4e2f5512b6f887f1d4f83" + "sha256:615f0d804180e6137bb0ad21f8f8496e592454256d27edc85da91f408183fc17", + "sha256:73ade350e710e20620e19ff3bb232e0300a5a7b0ff8d4ea556ee1e3a042572c3" ], "index": "pypi", - "version": "==6.41.5" + "version": "==6.41.10" }, "defusedxml": { "hashes": [ @@ -251,11 +251,11 @@ }, "django-import-export": { "hashes": [ - "sha256:39a4216c26a2dba6429b64c68b3fe282a6279bb71afb4015c13df0696bdbb4cd", - "sha256:dffedd53bed33cfcceb3b2f13d4fd93a21826f9a2ae37b9926a1e1f4be24bcb9" + "sha256:2eac09e8cec8670f36e24314760448011ad23c51e8fb930d55f50d0c3c926da0", + "sha256:4deabc557801d368093608c86fd0f4831bc9540e2ea41ca2f023e2efb3eb6f48" ], "markers": "python_version >= '3.8'", - "version": "==3.3.7" + "version": "==3.3.8" }, "django-js-reverse": { "hashes": [ @@ -451,11 +451,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "importlib-metadata": { "hashes": [ @@ -687,93 +687,94 @@ }, "pillow": { "hashes": [ - "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", - "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", - "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", - "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", - "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", - "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", - "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", - "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", - "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", - "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", - "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", - "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", - "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", - "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", - "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", - "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", - "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", - "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", - "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", - "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", - "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", - "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", - "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", - "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", - "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", - "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", - "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", - "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", - "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", - "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", - "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", - "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", - "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", - "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", - "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", - "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", - "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", - "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", - "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", - "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", - "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", - "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", - "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", - "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", - "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", - "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", - "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", - "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", - "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", - "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", - "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", - "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", - "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", - "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", - "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", - "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", - "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", - "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", - "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", - "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", - "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", - "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", - "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", - "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", - "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", - "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", - "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", - "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" + "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c", + "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2", + "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb", + "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d", + "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa", + "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3", + "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1", + "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a", + "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd", + "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8", + "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999", + "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599", + "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936", + "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375", + "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d", + "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b", + "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60", + "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572", + "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3", + "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced", + "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f", + "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b", + "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19", + "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f", + "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d", + "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383", + "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795", + "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355", + "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57", + "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09", + "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b", + "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462", + "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf", + "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f", + "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a", + "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad", + "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9", + "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d", + "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45", + "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994", + "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d", + "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338", + "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463", + "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451", + "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591", + "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c", + "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd", + "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32", + "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9", + "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf", + "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5", + "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828", + "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3", + "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5", + "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2", + "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b", + "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2", + "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475", + "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3", + "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb", + "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef", + "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015", + "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002", + "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170", + "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84", + "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57", + "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f", + "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27", + "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a" ], "markers": "python_version >= '3.8'", - "version": "==10.2.0" + "version": "==10.3.0" }, "pyasn1": { "hashes": [ - "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58", - "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c" + "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c", + "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.5.1" + "markers": "python_version >= '3.8'", + "version": "==0.6.0" }, "pyasn1-modules": { "hashes": [ - "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c", - "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d" + "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6", + "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.3.0" + "markers": "python_version >= '3.8'", + "version": "==0.4.0" }, "pydantic": { "hashes": [ @@ -855,7 +856,7 @@ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, "pytz": { @@ -1004,7 +1005,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "sortedcontainers": { @@ -1039,11 +1040,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", - "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "markers": "python_version >= '3.8'", - "version": "==4.10.0" + "version": "==4.11.0" }, "tzdata": { "hashes": [ @@ -1071,11 +1072,11 @@ }, "werkzeug": { "hashes": [ - "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc", - "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10" + "sha256:3aac3f5da756f93030740bc235d3e09449efcf65f2f55e3602e1d851b8f48795", + "sha256:e39b645a6ac92822588e7b39a692e7828724ceae0b0d702ef96701f90e70128d" ], "markers": "python_version >= '3.8'", - "version": "==3.0.1" + "version": "==3.0.2" }, "xlrd": { "hashes": [ @@ -1335,19 +1336,19 @@ }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "iniconfig": { "hashes": [ @@ -1608,19 +1609,19 @@ }, "types-requests": { "hashes": [ - "sha256:47872893d65a38e282ee9f277a4ee50d1b28bd592040df7d1fdaffdf3779937d", - "sha256:b1c1b66abfb7fa79aae09097a811c4aa97130eb8831c60e47aee4ca344731ca5" + "sha256:4428df33c5503945c74b3f42e82b181e86ec7b724620419a2966e2de604ce1a1", + "sha256:6216cdac377c6b9a040ac1c0404f7284bd13199c0e1bb235f4324627e8898cf5" ], "markers": "python_version >= '3.8'", - "version": "==2.31.0.20240311" + "version": "==2.31.0.20240406" }, "typing-extensions": { "hashes": [ - "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", - "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "markers": "python_version >= '3.8'", - "version": "==4.10.0" + "version": "==4.11.0" }, "urllib3": { "hashes": [ diff --git a/codeforlife/models/signals/pre_save.py b/codeforlife/models/signals/pre_save.py index 4787f79..44aeb10 100644 --- a/codeforlife/models/signals/pre_save.py +++ b/codeforlife/models/signals/pre_save.py @@ -48,7 +48,8 @@ def get_previous_value(field: str): return None else: - previous_instance = instance.__class__.objects.get(pk=instance.pk) + objects = instance.__class__.objects # type: ignore[attr-defined] + previous_instance = objects.get(pk=instance.pk) def get_previous_value(field: str): return getattr(previous_instance, field) diff --git a/codeforlife/tests/__init__.py b/codeforlife/tests/__init__.py index 9e95e79..fdaee24 100644 --- a/codeforlife/tests/__init__.py +++ b/codeforlife/tests/__init__.py @@ -13,5 +13,5 @@ ModelListSerializerTestCase, ModelSerializerTestCase, ) -from .model_view_set import ModelViewSetTestCase -from .test import TestCase +from .model_view_set import ModelViewSetClient, ModelViewSetTestCase +from .test import Client, TestCase diff --git a/codeforlife/tests/api.py b/codeforlife/tests/api.py index 5001cca..bacb3d5 100644 --- a/codeforlife/tests/api.py +++ b/codeforlife/tests/api.py @@ -125,7 +125,9 @@ def _login_user_type(self, user_type: t.Type[LoginUser], **credentials): otp = user.totp.at(now) with patch.object(timezone, "now", return_value=now): assert super().login( - request=self.request_factory.post(user=user), + request=self.request_factory.post( + user=t.cast(RequestUser, user) + ), otp=otp, ), f'Failed to login with OTP "{otp}" at {now}.' diff --git a/codeforlife/tests/model.py b/codeforlife/tests/model.py index 6c2c771..c1067d0 100644 --- a/codeforlife/tests/model.py +++ b/codeforlife/tests/model.py @@ -6,6 +6,7 @@ import typing as t from unittest.case import _AssertRaisesContext +from django.core.exceptions import ObjectDoesNotExist from django.db.models import Model from django.db.utils import IntegrityError @@ -76,8 +77,9 @@ def assert_does_not_exist(self, model_or_pk: t.Union[AnyModel, t.Any]): """ model_class = self.get_model_class() - with self.assertRaises(model_class.DoesNotExist): + with self.assertRaises(ObjectDoesNotExist): if isinstance(model_or_pk, Model): model_or_pk.refresh_from_db() else: - model_class.objects.get(pk=model_or_pk) + objects = model_class.objects # type: ignore[attr-defined] + objects.get(pk=model_or_pk) diff --git a/codeforlife/tests/model_view_set.py b/codeforlife/tests/model_view_set.py index dfbc9d5..a94dd86 100644 --- a/codeforlife/tests/model_view_set.py +++ b/codeforlife/tests/model_view_set.py @@ -8,6 +8,7 @@ import typing as t from datetime import datetime +from django.core.exceptions import ObjectDoesNotExist from django.db.models import Model from django.db.models.query import QuerySet from django.urls import reverse @@ -19,7 +20,7 @@ from ..serializers import BaseSerializer from ..types import DataDict, JsonDict, KwArgs from ..user.models import AnyUser as RequestUser -from ..user.models import User +from ..user.models import Class, Student, User from ..views import ModelViewSet from .api import APIClient, APITestCase @@ -681,8 +682,13 @@ def assert_serialized_model_equals_json_model( """ # Get the logged-in user. try: - user = User.objects.get(session=self.client.session.session_key) - except User.DoesNotExist: + user = t.cast( + RequestUser, + self.get_request_user_class().objects.get( + session=self.client.session.session_key + ), + ) + except ObjectDoesNotExist: user = None # NOTE: no user has logged in. # Create an instance of the model view set and serializer. @@ -844,7 +850,9 @@ def get_another_school_user( school = ( user.teacher.school if user.teacher - else user.student.class_field.teacher.school + else t.cast( + Class, t.cast(Student, user.student).class_field + ).teacher.school ) assert school @@ -882,12 +890,14 @@ def get_another_school_user( ) # Else, both users are students. else: + klass = t.cast( + Class, t.cast(Student, user.student).class_field + ) + assert ( - user.student.class_field - == other_user.student.class_field + klass == other_user.student.class_field if same_class - else user.student.class_field - != other_user.student.class_field + else klass != other_user.student.class_field ) else: assert school != other_school diff --git a/codeforlife/tests/test.py b/codeforlife/tests/test.py index 015539c..712b4af 100644 --- a/codeforlife/tests/test.py +++ b/codeforlife/tests/test.py @@ -3,12 +3,40 @@ Created on 10/04/2024 at 13:03:00(+01:00). """ +import typing as t from unittest.case import _AssertRaisesContext from django.core.exceptions import ValidationError +from django.http import HttpResponse +from django.test import Client as _Client from django.test import TestCase as _TestCase +class Client(_Client): + """A Django client with type hints.""" + + def generic(self, *args, **kwargs): + return t.cast(HttpResponse, super().generic(*args, **kwargs)) + + def get(self, *args, **kwargs): + return t.cast(HttpResponse, super().get(*args, **kwargs)) + + def post(self, *args, **kwargs): + return t.cast(HttpResponse, super().post(*args, **kwargs)) + + def put(self, *args, **kwargs): + return t.cast(HttpResponse, super().put(*args, **kwargs)) + + def patch(self, *args, **kwargs): + return t.cast(HttpResponse, super().patch(*args, **kwargs)) + + def delete(self, *args, **kwargs): + return t.cast(HttpResponse, super().delete(*args, **kwargs)) + + def options(self, *args, **kwargs): + return t.cast(HttpResponse, super().options(*args, **kwargs)) + + class TestCase(_TestCase): """Base test case for all tests to inherit.""" diff --git a/codeforlife/urls.py b/codeforlife/urls.py index 0e7cbeb..a7263a6 100644 --- a/codeforlife/urls.py +++ b/codeforlife/urls.py @@ -3,11 +3,13 @@ Created on 12/04/2024 at 14:42:20(+01:00). """ +import typing as t + from django.contrib import admin from django.contrib.auth.views import LogoutView from django.http import HttpResponse from django.shortcuts import render -from django.urls import include, path, re_path +from django.urls import URLPattern, URLResolver, include, path, re_path from rest_framework import status from .settings import SERVICE_IS_ROOT, SERVICE_NAME @@ -31,7 +33,7 @@ def service_urlpatterns( """ # Specific url patterns. - urlpatterns = [ + urlpatterns: t.List[t.Union[URLResolver, URLPattern]] = [ path( "admin/", admin.site.urls, diff --git a/codeforlife/user/auth/backends/user_id_and_login_id.py b/codeforlife/user/auth/backends/user_id_and_login_id.py index 8bda96b..6565174 100644 --- a/codeforlife/user/auth/backends/user_id_and_login_id.py +++ b/codeforlife/user/auth/backends/user_id_and_login_id.py @@ -5,7 +5,12 @@ import typing as t -from common.helpers.generators import get_hashed_login_id +# isort: off +from common.helpers.generators import ( # type: ignore[import-untyped] + get_hashed_login_id, +) + +# isort: on from ....request import HttpRequest from ...models import Student, StudentUser diff --git a/codeforlife/user/auth/password_validators/__init__.py b/codeforlife/user/auth/password_validators/__init__.py index 510580a..c10efbb 100644 --- a/codeforlife/user/auth/password_validators/__init__.py +++ b/codeforlife/user/auth/password_validators/__init__.py @@ -3,6 +3,6 @@ Created on 30/01/2024 at 12:28:00(+00:00). """ -from .student import StudentPasswordValidator from .independent import IndependentPasswordValidator +from .student import StudentPasswordValidator from .teacher import TeacherPasswordValidator diff --git a/codeforlife/user/filters/user.py b/codeforlife/user/filters/user.py index 54e6301..1aa1286 100644 --- a/codeforlife/user/filters/user.py +++ b/codeforlife/user/filters/user.py @@ -3,7 +3,9 @@ Created on 03/04/2024 at 16:37:44(+01:00). """ -from django_filters import rest_framework as filters +from django_filters import ( # type: ignore[import-untyped] # isort: skip + rest_framework as filters, +) from ..models import User diff --git a/codeforlife/user/models/klass.py b/codeforlife/user/models/klass.py index 156237a..fb34bdd 100644 --- a/codeforlife/user/models/klass.py +++ b/codeforlife/user/models/klass.py @@ -4,4 +4,4 @@ """ # pylint: disable-next=unused-import -from common.models import Class +from common.models import Class # type: ignore[import-untyped] diff --git a/codeforlife/user/models/school.py b/codeforlife/user/models/school.py index 55cdeb8..6c09c1e 100644 --- a/codeforlife/user/models/school.py +++ b/codeforlife/user/models/school.py @@ -4,4 +4,4 @@ """ # pylint: disable-next=unused-import -from common.models import School +from common.models import School # type: ignore[import-untyped] diff --git a/codeforlife/user/models/student.py b/codeforlife/user/models/student.py index dd01abb..f32eead 100644 --- a/codeforlife/user/models/student.py +++ b/codeforlife/user/models/student.py @@ -1,3 +1,5 @@ +# TODO: remove this in new system +# mypy: disable-error-code="import-untyped" """ ยฉ Ocado Group Created on 14/02/2024 at 17:16:44(+00:00). diff --git a/codeforlife/user/models/teacher.py b/codeforlife/user/models/teacher.py index 93b513e..b0a07fb 100644 --- a/codeforlife/user/models/teacher.py +++ b/codeforlife/user/models/teacher.py @@ -1,3 +1,5 @@ +# TODO: remove this in new system +# mypy: disable-error-code="import-untyped" """ ยฉ Ocado Group Created on 05/02/2024 at 09:49:56(+00:00). diff --git a/codeforlife/user/models/user.py b/codeforlife/user/models/user.py index 3a277b9..cad4231 100644 --- a/codeforlife/user/models/user.py +++ b/codeforlife/user/models/user.py @@ -1,3 +1,5 @@ +# TODO: remove this in new system +# mypy: disable-error-code="import-untyped" """ ยฉ Ocado Group Created on 05/02/2024 at 09:50:04(+00:00). diff --git a/setup.py b/setup.py index e7ccda3..dd65c23 100644 --- a/setup.py +++ b/setup.py @@ -88,6 +88,7 @@ def parse_requirements(packages: t.Dict[str, t.Dict[str, t.Any]]): long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/ocadotechnology/codeforlife-package-python", + # TODO: exclude test files packages=find_packages(exclude=["tests", "tests.*"]), include_package_data=True, data_files=[get_data_files(DATA_DIR), get_data_files(USER_FIXTURES_DIR)],