diff --git a/.github/workflows/common-business-dissolution.yml b/.github/workflows/common-business-dissolution.yml new file mode 100644 index 0000000000..9a660240cf --- /dev/null +++ b/.github/workflows/common-business-dissolution.yml @@ -0,0 +1,21 @@ +name: Common Business Dissolution CI + +on: + pull_request: + types: [assigned, synchronize] + paths: + - "python/common/business-registry-dissolution/**" + workflow_dispatch: + +defaults: + run: + shell: bash + working-directory: ./python/common/business-registry-dissolution + +jobs: + business-registry-dissolution-ci: + uses: bcgov/bcregistry-sre/.github/workflows/backend-ci.yaml@main + with: + app_name: "business-registry-dissolution" + working_directory: "./python/common/business-registry-dissolution" + codecov_flag: "business-registry-dissolution" \ No newline at end of file diff --git a/python/common/business-registry-dissolution/poetry.lock b/python/common/business-registry-dissolution/poetry.lock index fe97ac1293..c9d49a6ca1 100644 --- a/python/common/business-registry-dissolution/poetry.lock +++ b/python/common/business-registry-dissolution/poetry.lock @@ -99,51 +99,6 @@ files = [ [package.extras] dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] -[[package]] -name = "black" -version = "25.1.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, - {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, - {file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"}, - {file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"}, - {file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"}, - {file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"}, - {file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"}, - {file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"}, - {file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"}, - {file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"}, - {file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"}, - {file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"}, - {file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"}, - {file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"}, - {file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"}, - {file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"}, - {file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"}, - {file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"}, - {file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"}, - {file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"}, - {file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"}, - {file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.10)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "blinker" version = "1.9.0" @@ -158,7 +113,7 @@ files = [ [[package]] name = "business-model" -version = "3.3.22" +version = "3.3.30" description = "" optional = false python-versions = ">=3.13,<3.14" @@ -178,60 +133,62 @@ pg8000 = ">=1.31.2,<2.0.0" pycountry = ">=24.6.1,<25.0.0" pydantic = ">=2.10.6,<3.0.0" pytz = ">=2025.1,<2026.0" -registry-schemas = {git = "https://github.com/bcgov/business-schemas.git", rev = "2.18.62"} +registry-schemas = {git = "https://github.com/bcgov/business-schemas.git", rev = "2.18.69"} sql-versioning = {git = "https://github.com/bcgov/lear.git", rev = "main", subdirectory = "python/common/sql-versioning-alt"} [package.source] type = "git" url = "https://github.com/bcgov/lear.git" -reference = "HEAD" -resolved_reference = "0078d2e1d22319c9875e06ad77ee680973c09552" +reference = "main" +resolved_reference = "c9c4669cbe5630e05a48179619c7c19432e6fdec" subdirectory = "python/common/business-registry-model" [[package]] name = "business-registry-account" -version = "0.1.0" +version = "0.1.1" description = "" optional = false -python-versions = "^3.13" +python-versions = ">=3.13,<3.14" groups = ["main"] files = [] develop = false [package.dependencies] -datedelta = "^1.4" -flask = "^3.1.0" -flask-jwt-oidc = "^0.8.0" -python-dotenv = "^1.0.1" -pytz = "^2025.1" -requests = "^2.32.3" +datedelta = ">=1.4,<2.0" +flask = ">=3.1.0,<4.0.0" +flask-jwt-oidc = ">=0.8.0,<1.0.0" +python-dotenv = ">=1.1.0,<2.0.0" +pytz = ">=2025.1,<2026.0" +requests = ">=2.32.3,<3.0.0" [package.source] type = "git" url = "https://github.com/bcgov/lear.git" -reference = "HEAD" -resolved_reference = "67cc9c452dcc602a9c0d740ebe059fd694180616" +reference = "main" +resolved_reference = "ab74265227677d93896a8d9c85dd5bae6c617873" subdirectory = "python/common/business-registry-account" [[package]] name = "business-registry-common" -version = "0.1.0" +version = "0.1.1" description = "" optional = false -python-versions = ">=3.9,<4.0" +python-versions = ">=3.13,<3.14" groups = ["main"] files = [] develop = false [package.dependencies] -datedelta = "^1.4" -pytz = "^2025.1" +datedelta = ">=1.4,<2.0" +flask = ">=3.1.0,<4.0.0" +python-dateutil = ">=2.9.0,<3.0.0" +pytz = ">=2025.1,<2026.0" [package.source] type = "git" url = "https://github.com/bcgov/lear.git" -reference = "HEAD" -resolved_reference = "d844169681baed690b77df9617897414cd5c42ff" +reference = "main" +resolved_reference = "ab74265227677d93896a8d9c85dd5bae6c617873" subdirectory = "python/common/business-registry-common" [[package]] @@ -252,7 +209,7 @@ version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main"] +groups = ["main", "test"] files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, @@ -345,7 +302,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["main"] +groups = ["main", "test"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -447,7 +404,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -462,12 +419,131 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] +groups = ["main", "test"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} +markers = {main = "platform_system == \"Windows\"", test = "sys_platform == \"win32\""} + +[[package]] +name = "coverage" +version = "7.14.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["test"] +files = [ + {file = "coverage-7.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3e3680291c4a1d0dadfa84a2c459576a4af5133abb617905714339a0c73138cf"}, + {file = "coverage-7.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5274669f37f2343635a347b91a60777621341ab3378e9c6ac9335eee704bddf"}, + {file = "coverage-7.14.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cfe5a5fec635799ef33428f1e5e61bafa45a92a96190ba731561ba558ccc214d"}, + {file = "coverage-7.14.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:62a9f70b52e0b5a95cfef4a5c5641b06983cadc5e538a3feeb5c00211f523ac2"}, + {file = "coverage-7.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c18ebc343e15be53049b3a2dce38fe82d58f37e20ab9094b3a39c0aa4f6bb47"}, + {file = "coverage-7.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b84ffdf877644e7096aa936991efeed873f7f3df57b9cd001312b7668ab08550"}, + {file = "coverage-7.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e854312c4103f2ad4c0dc023b69b77ebfd2c89db5f86c4c94dc2353f9a92167e"}, + {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c643734307300234fafa36bf2a040a7235f8f177ea1fd6ec1423aea6fb7b929f"}, + {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84ac9499e48700399a5dd0ea7085b5091961fec52c68d66b4ec0d3cf7f4441b1"}, + {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7f02d09f70776579b926d889a4c9c235070a1f47c40458aeaca563fae5acfdb5"}, + {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ce66d8e46da2bb5ee313a745cbd2e391d319176c1f7a9451bfcd3a2fb920859b"}, + {file = "coverage-7.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c912c259304cfb5ee584481cfb7ce1ff932b4d61e6c9140b8f19cb7b5ed82332"}, + {file = "coverage-7.14.1-cp310-cp310-win32.whl", hash = "sha256:1238cb94638e610e972c60dac68e813f868dc7d6e982535270558443058d9d59"}, + {file = "coverage-7.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:fc459e5d73be2d6332fcfe8dbf3d8994671fe33c700f4565988ecfa511547253"}, + {file = "coverage-7.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:478b5bcd63c2e1357c5c7e16c070690df7b07f676b1c114d7b93e533c664309f"}, + {file = "coverage-7.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a24a81f9715ee42ef59a316cc11611c98fe23920f7c81861315c9f3ff4a230f4"}, + {file = "coverage-7.14.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:196a13319ad88d6d8ef5ab489ec4f44ddde2143c0c7d5b27786f6c3ffd56a7e1"}, + {file = "coverage-7.14.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d452fd08b5c72c5167c93e6867b5c08500bd40f2a21e1e854a500550b6cc36f"}, + {file = "coverage-7.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23bf7fa51ac02e07fc7c96849b82946da47ae862dc8f86d183b2a4864fc38129"}, + {file = "coverage-7.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcaa50684dcaadfa599ac48f81103c756d791cfd85c97203d2217c593d48b860"}, + {file = "coverage-7.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4ea1c034f95c9b056e856b794630b17f9fa3d57e4800ff1e503d3be0f9c9078c"}, + {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e057326434e441306226fbeb5d1aaf14a2637efe97ba668306635835f32ad7"}, + {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:59baf88468dbc8d63b1887afd92bda52e40bb1561696e5819670601403810cec"}, + {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d75f892b3ab73ba11cab5442cce7b3e168fd64162b16f0e1e0d09c508edef"}, + {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3a56abc20a472baf0304c455721bc601477440d28ecfde8a03dde79ede07e0df"}, + {file = "coverage-7.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6a3cb83d1552c0cd1b4906655b6a33fd4a8473229633a901c6b73bf86914dee9"}, + {file = "coverage-7.14.1-cp311-cp311-win32.whl", hash = "sha256:10274a1fbeb8ec5d72966e17bb198a3104257aca4ac09d98667c5f8aca8c8548"}, + {file = "coverage-7.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:87ebdf787d4888e3f3f2d523eadc6e18c6d18c6d0eb173801a189641627fb37e"}, + {file = "coverage-7.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:dd34767fa19848d35659ffc0a75314f58c7af3f1cd87ec521e8292a1238398a3"}, + {file = "coverage-7.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a06c76364a9360e33d6d23769aefdf7f66f38e2ffb60ceb1baaa4989d83b695c"}, + {file = "coverage-7.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fad54e871165f6ec2f536063ac74c3104508a12963e64072ba44bd822de52b0c"}, + {file = "coverage-7.14.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:84b535f00655ecafe1d929d1fb00ed5d6fa3051ea643ab2c161a3887b86f294b"}, + {file = "coverage-7.14.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6b6b0853b895fe0e98cbfc580d1ec3393d9302b4b1e96a77b3f5c91fdab899e6"}, + {file = "coverage-7.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:442cc9c952b2df400cda54bb04ab87330cf2cd08a8692cbbea36773531eb6f37"}, + {file = "coverage-7.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8270544c361ed405a27a060dbc9ed2c124b084d96dfdc2d9a2510482aef981ad"}, + {file = "coverage-7.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:48b283b1dd6372e8de2a7a9a4c4d5dc06f4d4fd209b876f3c88a7a205a0c8f84"}, + {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5b0c99ba93a07d56f6df340bb79be53202a082b2fdb81bfe6190b741a3470d54"}, + {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e471bc5769ff073b058cfadb0d736b56ce067c8560eabeb0da88462df98c23e7"}, + {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f497a1ea81d4cd7c10ddcaa685135b9aabd291af3d55775a9ddf3cb7a364cdd9"}, + {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2222be86d0b54f5dd5a38f45f17f315f737245e857bf0bdedc70734f84a13c02"}, + {file = "coverage-7.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85e85586565842f6932abebd4c18bcb1074223dc0b3576e7d173ca710622813a"}, + {file = "coverage-7.14.1-cp312-cp312-win32.whl", hash = "sha256:4a28fd227808366b196a75476dced2eb35b351d6766ba9c858dc93319e87f4f1"}, + {file = "coverage-7.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:54acdb6674a4661768d7bf7db32dfb9f46ab1d764f8aba6df75ce1a6a088724e"}, + {file = "coverage-7.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:99cd41ff91afd94896fea3bc002706b6ae4ce95727d06e4a0f39c0a8d8bd8b1a"}, + {file = "coverage-7.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:be9f2c802dcfce3f71298303aa5dad0dce440a76c52f2f60dacd8656dab78793"}, + {file = "coverage-7.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6223a72fd0e4c7156353ec0f08a5f93623e1d3034d0e2683b9bb8ea674131b1d"}, + {file = "coverage-7.14.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7279d2110a28cebc738b6459ecda2771735a4c18465fbbd36b3288fe5ed92247"}, + {file = "coverage-7.14.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9eeb3fcbc13ba40dfbdb22d01d196a28e9cef9ed4c29b60061a1e0e823a9929d"}, + {file = "coverage-7.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f0cfc27c539f07cf5c0a4cfe211d0b6cae039f8f40526dbaa71944e64b50a7b"}, + {file = "coverage-7.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:221c70f316241a78e77e607c227cefc8808d4e08f28d99c04f35694690e940be"}, + {file = "coverage-7.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:da028256b04ec30e5e0114b6f76172938c313991f0a2d3d894271315cf5d5e43"}, + {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76a085d7005236a767e3426148b2c407e53ad61695c562f8a81da2d373324901"}, + {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b553d04b5e778a8e56d57eb134aff42a92718ecba45e79c4764ecfa40efd92ff"}, + {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:46f714d2fb8ae2f4f29f23ada7f1e79b759fff5a70f94a1dac23af204c3ec9e4"}, + {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1896f5e19ff3f0431c7ce2172adc54890fd97f86b59ced8ca1649145d9ffe35d"}, + {file = "coverage-7.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:62fd185ef9df3c33d1c8178c5af105f762afbad96038de9a4ae100aa6297ca33"}, + {file = "coverage-7.14.1-cp313-cp313-win32.whl", hash = "sha256:ab4af6352741a604c431c6072fce5bee33bf0f20dc7a56618d6bf6bb89e9810c"}, + {file = "coverage-7.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:7af486dabe8954d03b087f0021540897afe084f04e16ff5579e08cc46f871416"}, + {file = "coverage-7.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:2224f89ffd0c5605ccce1ed7a584da162bc7c55f601ab1c946bc9de31a486b42"}, + {file = "coverage-7.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de286598cc65d2b489411174b1faec2f5a7775fb3201fd925db2a76b4030f37d"}, + {file = "coverage-7.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:042c46ded7c288aeb07cf14a28b6c1e10b78fcba40171c3fa1e939377eeef0b5"}, + {file = "coverage-7.14.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f4ddbe407477f04c45115d1a4e5bc480f753553b534d338d4c3358b1cdd0ea52"}, + {file = "coverage-7.14.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d13e6725992e2d2fd7d81d4f5241952d13740121dfd501da09201be39b2c003a"}, + {file = "coverage-7.14.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f747dc8edcfe740130f28f32f3995e955494285717e86ee25af51db2219df08a"}, + {file = "coverage-7.14.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ced2f09ef276fd58611a1ef502164ad266d2b75174e5a40cabbdb4033f9f6cf2"}, + {file = "coverage-7.14.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b84800013769a78ccb9ef4659402e26d06867e337b61ec365f77ad008adea80e"}, + {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ea8cd6ca0ee9f616aaef3afc6882e32c2cbf18b00d96313ffd76af650574034d"}, + {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:aa5e304a873fabddc11e484e9b6b738bd38bd7bed17b09aa84eecf5332e8b8bb"}, + {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5a1c5215be81035e629d5bc756650634d0bf31991038db7a0eccb90f025ce16d"}, + {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:79058c47dae6788504b5effb319961bcd72d7240551464b91d474bc0ed186d69"}, + {file = "coverage-7.14.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:370c5afae3fa0658e11694a32b24c2778f6bc2d17718121f94ee185e69f26b54"}, + {file = "coverage-7.14.1-cp313-cp313t-win32.whl", hash = "sha256:3758dd0a7f1fa57365ef2e781df0f0731d38b6e3772259d13dae4bd8a958d4b1"}, + {file = "coverage-7.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:6ff665fb023a77386fe11685190cee1f60a7d635994a30d9b0a061533d470fce"}, + {file = "coverage-7.14.1-cp313-cp313t-win_arm64.whl", hash = "sha256:17a5a241e5997621a956a7f402a7433ef4221e5152809b785bec79e2323799f1"}, + {file = "coverage-7.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d5ed429d0b8edaac649e889b4ffcedb6c80b06629a3f93050e3dddfb99235bee"}, + {file = "coverage-7.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8011224a62280e50dab346960c03cf47aca1a1e09e608c0fb33fd6e0cc8e9500"}, + {file = "coverage-7.14.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:12c42ec1e14f553c4f817e989365982e646e27211f10a0f717855b94a79c8906"}, + {file = "coverage-7.14.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06144cd511cf2624873a035c5069cf297144f6e77a73ee3d7a55b605ec5efb42"}, + {file = "coverage-7.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a311d8e1da24be5c1ccf85cbfb06315dbaa1703d5a1eab3f6432c72b837917c8"}, + {file = "coverage-7.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c79cead5b5bc584d9c71451cb984d0e3a84e0c0937379c8efcbf27c8d661b851"}, + {file = "coverage-7.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dcbf65f1f66a26cdd88c35cf68fb4729c5d1cd2e88added72420541dfb212034"}, + {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fd86572566fb40189a8260446158235159bc7a82dfbc87a3b39cf4fb57fcec1c"}, + {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7771b601718fdde84832c3a434ca9bbf4ae9adbc49d84198b4110700c3c77c36"}, + {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:39b21e212c55af06fa375e3dbf90a8a8e38792f3a910c580066d23563830ddd5"}, + {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f2302660e32562a532b442480121aef8aa61a5bdb20b30bf0adab29f10a5a4b4"}, + {file = "coverage-7.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:03a6f93c1ec3b7f2e77b5dbcc5573a2c21f12529a5c6bbe0f16f72303cc2fa4d"}, + {file = "coverage-7.14.1-cp314-cp314-win32.whl", hash = "sha256:8a3ce026d73290f42f08dafecbd82c193a74df280461fbf97300fec51fd133ee"}, + {file = "coverage-7.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:114c95ef29302423b87d159075805f4ab973254a2638a5d7d046c94887cc87d7"}, + {file = "coverage-7.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:a07891c3f4805442b31b71e84ba3cf29ed1aa9a428284e06deeb4b23e5b46343"}, + {file = "coverage-7.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1101a5ebb083aecb625ebb6209d4105b58f647b093cb2dc8122d7b33f743cfe1"}, + {file = "coverage-7.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:851b9e1e4e8a4608e77c79714b2e77c0970d2ed7202a05e92ae407817481887b"}, + {file = "coverage-7.14.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d5b89cdfb2ee051b71e8c3c70bd81a9eff81100f736a269136fe1a68efe00474"}, + {file = "coverage-7.14.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0177614a0370f227888b4e436a7c55686d6a9f90eb1ade2b624ba685a1686e86"}, + {file = "coverage-7.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d69af5dea2de76fc485a83032a630523f985198b7e25be901ec60181587b01e"}, + {file = "coverage-7.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:35ab22d91de736e8966b980dc355cbcdd2c6dbbcfe275f9a2991bc8a91b3df65"}, + {file = "coverage-7.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:357d4e32935c36588aaba057d734fa32428c360c9fc2e4442afbf1b646beee6e"}, + {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:51bd64741cc6fa065abd300ede1afe5a5291ece9c31da8b24884deda48bcc3f8"}, + {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:9132cd363a68a4c3daa7c8704a654b1e39d3360f6f5b8ddd470608a945236c07"}, + {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:07c6290b1697b862c0478eab545eec949a0d0e4d6d03497f446d706da3b4f2de"}, + {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5ea0c297e27133853b4d8a3eb799bff5a2dbd9f2f41537a240d337ac9b4df890"}, + {file = "coverage-7.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:01b7733daad0237daa01ef80fe2dfceffc911e6a17fa7b55d14aa8214eaaaecd"}, + {file = "coverage-7.14.1-cp314-cp314t-win32.whl", hash = "sha256:6adc5a36984624a70bf11d7184e20fa0a49aa7c47ffab43804106a1a695ea22e"}, + {file = "coverage-7.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:ddf799247318f34dbcd2efa8c95a8d0642674e926bb1774cf9b63dfd2a389d1c"}, + {file = "coverage-7.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:145986fe66647eb489f18d9a997567a3fd358584c4b5a808769113abc07466af"}, + {file = "coverage-7.14.1-py3-none-any.whl", hash = "sha256:a252f21c27e38347e60111a3266b03827422a7d5525951aceee313aa68bab1d2"}, + {file = "coverage-7.14.1.tar.gz", hash = "sha256:30c08f7d90415aa98b3c990385dea2939b0da55f38515e5b369b83655f8523be"}, +] + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "croniter" @@ -549,7 +625,7 @@ version = "1.4" description = "Like datetime.timedelta, for date arithmetic." optional = false python-versions = ">=3.6,<4.0" -groups = ["main"] +groups = ["main", "test"] files = [ {file = "datedelta-1.4-py3-none-any.whl", hash = "sha256:9f7a8a2bd80d29d6cfe1036990979ea404c8e1ddbc5a73cff74d283186d12b4d"}, {file = "datedelta-1.4.tar.gz", hash = "sha256:3f1ef319ead642a76a3cab731917bf14a0ced0d91943f33ff57ae615837cab97"}, @@ -569,23 +645,6 @@ files = [ [package.dependencies] python-dotenv = "*" -[[package]] -name = "flake8" -version = "7.1.2" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -groups = ["dev"] -files = [ - {file = "flake8-7.1.2-py2.py3-none-any.whl", hash = "sha256:1cbc62e65536f65e6d754dfe6f1bada7f5cf392d6f5db3c2b85892466c3e7c1a"}, - {file = "flake8-7.1.2.tar.gz", hash = "sha256:c586ffd0b41540951ae41af572e6790dbd49fc12b3aa2541685d253d9bd504bd"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.12.0,<2.13.0" -pyflakes = ">=3.2.0,<3.3.0" - [[package]] name = "flake8-import-order" version = "0.18.2" @@ -718,7 +777,7 @@ version = "1.5.1" description = "Let your Python tests travel through time" optional = false python-versions = ">=3.7" -groups = ["dev"] +groups = ["test"] files = [ {file = "freezegun-1.5.1-py3-none-any.whl", hash = "sha256:bf111d7138a8abe55ab48a71755673dbaa4ab87f4cff5634a4442dfec34c15f1"}, {file = "freezegun-1.5.1.tar.gz", hash = "sha256:b29dedfcda6d5e8e083ce71b2b542753ad48cfec44037b3fc79702e2980a89e9"}, @@ -821,7 +880,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["main"] +groups = ["main", "test"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -836,7 +895,7 @@ version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.8" -groups = ["dev"] +groups = ["test"] files = [ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, @@ -1035,54 +1094,18 @@ files = [ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -groups = ["dev"] -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -groups = ["dev"] -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - [[package]] name = "packaging" version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["dev"] +groups = ["test"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - [[package]] name = "pg8000" version = "1.31.2" @@ -1099,30 +1122,13 @@ files = [ python-dateutil = ">=2.8.2" scramp = ">=1.4.5" -[[package]] -name = "platformdirs" -version = "4.3.7" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, - {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.14.1)"] - [[package]] name = "pluggy" version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" -groups = ["dev"] +groups = ["test"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1132,33 +1138,13 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "psycopg2" -version = "2.9.10" -description = "psycopg2 - Python-PostgreSQL Database Adapter" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "psycopg2-2.9.10-cp310-cp310-win32.whl", hash = "sha256:5df2b672140f95adb453af93a7d669d7a7bf0a56bcd26f1502329166f4a61716"}, - {file = "psycopg2-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:c6f7b8561225f9e711a9c47087388a97fdc948211c10a4bccbf0ba68ab7b3b5a"}, - {file = "psycopg2-2.9.10-cp311-cp311-win32.whl", hash = "sha256:47c4f9875125344f4c2b870e41b6aad585901318068acd01de93f3677a6522c2"}, - {file = "psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4"}, - {file = "psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067"}, - {file = "psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e"}, - {file = "psycopg2-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:91fd603a2155da8d0cfcdbf8ab24a2d54bca72795b90d2a3ed2b6da8d979dee2"}, - {file = "psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b"}, - {file = "psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442"}, - {file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"}, -] - [[package]] name = "pycodestyle" version = "2.12.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, @@ -1329,7 +1315,7 @@ version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, @@ -1359,7 +1345,7 @@ version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" -groups = ["dev"] +groups = ["test"] files = [ {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, @@ -1374,13 +1360,33 @@ pluggy = ">=1.5,<2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-cov" +version = "6.3.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +groups = ["test"] +files = [ + {file = "pytest_cov-6.3.0-py3-none-any.whl", hash = "sha256:440db28156d2468cafc0415b4f8e50856a0d11faefa38f30906048fe490f1749"}, + {file = "pytest_cov-6.3.0.tar.gz", hash = "sha256:35c580e7800f87ce892e687461166e1ac2bcb8fb9e13aea79032518d6e503ff2"}, +] + +[package.dependencies] +coverage = {version = ">=7.5", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=6.2.5" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev"] +groups = ["main", "test"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -1434,7 +1440,7 @@ rpds-py = ">=0.7.0" [[package]] name = "registry_schemas" -version = "2.18.62" +version = "2.18.69" description = "A short description of the project" optional = false python-versions = ">=3.6" @@ -1452,8 +1458,8 @@ strict-rfc3339 = "*" [package.source] type = "git" url = "https://github.com/bcgov/business-schemas.git" -reference = "2.18.62" -resolved_reference = "1cea81cf14104fb7d4989169236eff13b3df16c4" +reference = "2.18.69" +resolved_reference = "25282bd6cf4de87e9dc6bc44f619ed723b64c7f2" [[package]] name = "requests" @@ -1461,7 +1467,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["main", "test"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -1477,6 +1483,24 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "requests-mock" +version = "1.12.1" +description = "Mock out responses from the requests package" +optional = false +python-versions = ">=3.5" +groups = ["test"] +files = [ + {file = "requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401"}, + {file = "requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563"}, +] + +[package.dependencies] +requests = ">=2.22,<3" + +[package.extras] +fixture = ["fixtures"] + [[package]] name = "rfc3339-validator" version = "0.1.4" @@ -1628,6 +1652,34 @@ files = [ {file = "rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e"}, ] +[[package]] +name = "ruff" +version = "0.11.13" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46"}, + {file = "ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48"}, + {file = "ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71"}, + {file = "ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432"}, + {file = "ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492"}, + {file = "ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250"}, + {file = "ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3"}, + {file = "ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b"}, + {file = "ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514"}, +] + [[package]] name = "scramp" version = "1.4.5" @@ -1670,7 +1722,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev"] +groups = ["main", "test"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -1890,7 +1942,7 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["main"] +groups = ["main", "test"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -1952,4 +2004,4 @@ tomli = "*" [metadata] lock-version = "2.1" python-versions = ">=3.13,<3.14" -content-hash = "6fdda1f3bc2f1f4fb12258fd2f1b170538480b3ad14138f002f45a99fd37dacc" +content-hash = "67d6648063d51192a3ba4180430ba1e9b201f53b4f2f66d99708e4aa4cabbf05" diff --git a/python/common/business-registry-dissolution/poetry.toml b/python/common/business-registry-dissolution/poetry.toml new file mode 100644 index 0000000000..ab1033bd37 --- /dev/null +++ b/python/common/business-registry-dissolution/poetry.toml @@ -0,0 +1,2 @@ +[virtualenvs] +in-project = true diff --git a/python/common/business-registry-dissolution/pyproject.toml b/python/common/business-registry-dissolution/pyproject.toml index 2f51c46a59..3cd24b5b70 100644 --- a/python/common/business-registry-dissolution/pyproject.toml +++ b/python/common/business-registry-dissolution/pyproject.toml @@ -1,28 +1,169 @@ -[tool.poetry] +[project] name = "business-registry-dissolution" -version = "0.1.1" +version = "0.1.2" description = "" -authors = ["BrandonSharratt "] +authors = [{name = "BC Business Registry"}] readme = "README.md" +requires-python = ">=3.13,<3.14" +dependencies = [ + "flask (>=3.1.0,<4.0.0)", + "python-dotenv (>=1.1.0,<2.0.0)", + # BCReg deps + "business-model @ git+https://github.com/bcgov/lear.git@main#subdirectory=python/common/business-registry-model", + "business-registry-account @ git+https://github.com/bcgov/lear.git@main#subdirectory=python/common/business-registry-account", + "business-registry-common @ git+https://github.com/bcgov/lear.git@main#subdirectory=python/common/business-registry-common", +] + +[tool.poetry] packages = [{include = "dissolution_service", from = "src"}] -[tool.poetry.dependencies] -python = ">=3.13,<3.14" -flask = "^3.1.0" -sqlalchemy = "^2.0.39" +[tool.poetry.group.test.dependencies] datedelta = "^1.4" -business-model = {git = "https://github.com/bcgov/lear.git", subdirectory = "python/common/business-registry-model"} -business-registry-account = {git = "https://github.com/bcgov/lear.git", subdirectory = "python/common/business-registry-account"} -business-registry-common = {git = "https://github.com/bcgov/lear.git", subdirectory = "python/common/business-registry-common"} -flask-migrate = {version = ">=4.1.0,<5.0.0"} +freezegun = "^1.5.1" +pytest = "^8.3.5" +pytest-cov = "^6.0.0" +requests-mock = "^1.12.1" [tool.poetry.group.dev.dependencies] -pytest = "^8.3.5" -black = "^25.1.0" -flake8 = "^7.1.2" -psycopg2 = "^2.9.10" -freezegun = "^1.5.1" +ruff = "^0.11.5" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + +[tool.ruff] +# Exclude a variety of commonly ignored directories. +exclude = [ + ".vscode", + "dist", + "htmlcov", + ".venv", + "migrations", + "devops", + ".history" +] + + +# Same as Black. +line-length = 120 +indent-width = 4 + +# Assume Python 3.13 +target-version = "py313" + +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +# Enable auto-formatting of code examples in docstrings. Markdown, +# reStructuredText code/literal blocks and doctests are all supported. +# +# This is currently disabled by default, but it is planned for this +# to be opt-out in the future. +docstring-code-format = true + +# Set the line length limit used when formatting code snippets in +# docstrings. +# +# This only has an effect when the `docstring-code-format` setting is +# enabled. +docstring-code-line-length = "dynamic" + +[tool.ruff.lint] +select = [ + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "ERA", # flake8-eradicate/eradicate + "I", # isort + "N", # pep8-naming + "PIE", # flake8-pie + "PL", # pyLint + "PGH", # pygrep + "Q", # Enables flake8-quotes rules + "RUF", # ruff checks + "SIM", # flake8-simplify + "T20", # flake8-print + "TCH", # flake8-type-checking + "TID", # flake8-tidy-imports + "UP", # pyupgrade +] + +[tool.ruff.lint.per-file-ignores] +"**/config.py" = [ + "T201", # allow print instead of logger in config +] +"**/tests/*" = [ + "B", + "C", + "ERA", + "N", + "PLR", + "RUF", + "SIM", + "T2", +] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [ + "ERA", # do not autoremove commented out code +] + +[tool.ruff.lint.isort] +known-first-party = ["business_account", "business_common", "business_model", "flask_jwt_oidc"] + +[tool.ruff.lint.flake8-quotes] +docstring-quotes = "double" + +[tool.pytest.ini_options] +minversion = "2.0" +testpaths = [ + "tests", +] +addopts = "--verbose --strict -p no:warnings --cov=src --cov-report html:htmlcov --cov-report xml:coverage.xml" +python_files = [ + "test*.py" +] +norecursedirs = [ + ".git", ".tox", "venv*", "requirements*", "build", +] +log_cli = true +log_cli_level = "INFO" +filterwarnings = [ + "ignore::UserWarning" +] +markers = [ + "slow", + "serial", +] + +[tool.coverage.run] +branch = true +source = [ + "src/dissolution_service", +] +omit = [ +] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "from", + "import", + "def __repr__", + "if self.debug:", + "if settings.DEBUG", + "raise AssertionError", + "raise NotImplementedError", + "if 0:", + 'if __name__ == "__main__":', +] diff --git a/python/common/business-registry-dissolution/src/dissolution_service/config.py b/python/common/business-registry-dissolution/src/dissolution_service/config.py index d8fc77a08a..f08879f1a8 100644 --- a/python/common/business-registry-dissolution/src/dissolution_service/config.py +++ b/python/common/business-registry-dissolution/src/dissolution_service/config.py @@ -24,35 +24,34 @@ from dotenv import find_dotenv, load_dotenv - # this will load all the envars from a .env file located in the project root (api) load_dotenv(find_dotenv()) CONFIGURATION = { - 'development': 'business_account.config.DevConfig', - 'testing': 'business_account.config.TestConfig', - 'production': 'business_account.config.ProdConfig', - 'default': 'business_account.config.ProdConfig' + "development": "business_account.config.DevConfig", + "testing": "business_account.config.TestConfig", + "production": "business_account.config.ProdConfig", + "default": "business_account.config.ProdConfig" } -def get_named_config(config_name: str = 'production'): +def get_named_config(config_name: str = "production"): """Return the configuration object based on the name. :raise: KeyError: if an unknown configuration is requested """ - if config_name in ['production', 'staging', 'default']: + if config_name in ["production", "staging", "default"]: config = ProdConfig() - elif config_name == 'testing': + elif config_name == "testing": config = TestConfig() - elif config_name == 'development': + elif config_name == "development": config = DevConfig() else: - raise KeyError(f'Unknown configuration: {config_name}') + raise KeyError(f"Unknown configuration: {config_name}") return config -class _Config(): # pylint: disable=too-few-public-methods +class _Config: # pylint: disable=too-few-public-methods """Base class configuration that should set reasonable defaults. Used as the base for all the other configurations. diff --git a/python/common/business-registry-dissolution/src/dissolution_service/involuntary_dissolution.py b/python/common/business-registry-dissolution/src/dissolution_service/involuntary_dissolution.py index 30eb1c8cd6..d6a30d2d5d 100644 --- a/python/common/business-registry-dissolution/src/dissolution_service/involuntary_dissolution.py +++ b/python/common/business-registry-dissolution/src/dissolution_service/involuntary_dissolution.py @@ -14,18 +14,19 @@ """This provides the service for involuntary dissolution.""" from dataclasses import dataclass -from typing import Final, Tuple +from typing import Any, Final from sqlalchemy import and_, exists, func, not_, or_, select, text from sqlalchemy.orm import aliased +from business_account import AccountService +from business_common.core.filing import Filing as CoreFiling from business_model.models import Batch, BatchProcessing, Business, Filing, db -from business_account.AccountService import AccountService -from business_common.core.filing import Filing as CoreFiling # pylint: disable=import-outside-toplevel +from .request_context import get_request_context -class InvoluntaryDissolutionService(): +class InvoluntaryDissolutionService: """Provides services to get information for involuntary dissolution.""" ELIGIBLE_TYPES: Final = [ @@ -57,14 +58,15 @@ class EligibilityFilters: @classmethod def check_business_eligibility( - cls, identifier: str, eligibility_filters: EligibilityFilters = EligibilityFilters(), flags: any = None - ) -> Tuple[bool, EligibilityDetails]: + cls, identifier: str, eligibility_filters: EligibilityFilters | None = None, flags: Any = None + ) -> tuple[bool, EligibilityDetails]: """Return true if the business with provided identifier is eligible for dissolution. Returns: eligible (bool): True if the business is eligible for dissolution. eligibility_details (EligibilityDetails): Details regarding eligibility. """ + eligibility_filters = eligibility_filters or cls.EligibilityFilters() query = cls._get_businesses_eligible_query(eligibility_filters, flags).filter(Business.identifier == identifier) result = query.one_or_none() @@ -75,18 +77,15 @@ def check_business_eligibility( return True, eligibility_details @classmethod - def get_businesses_eligible(cls, num_allowed: int = None, flags: any = None): + def get_businesses_eligible(cls, num_allowed: int | None = None, flags: Any = None): """Return the businesses eligible for involuntary dissolution.""" query = cls._get_businesses_eligible_query(flags=flags) - if num_allowed: - eligible_businesses = query.limit(num_allowed).all() - else: - eligible_businesses = query.all() + eligible_businesses = query.limit(num_allowed).all() if num_allowed else query.all() return eligible_businesses @classmethod - def get_businesses_eligible_count(cls, flags: any = None): + def get_businesses_eligible_count(cls, flags: Any = None): """Return the number of businesses eligible for involuntary dissolution.""" return cls._get_businesses_eligible_query(flags=flags).count() @@ -103,12 +102,13 @@ def get_in_dissolution_batch_processing(business_id: int): one_or_none() @staticmethod - def _get_businesses_eligible_query(eligibility_filters: EligibilityFilters = EligibilityFilters(), flags: any = None): + def _get_businesses_eligible_query(eligibility_filters: EligibilityFilters | None = None, flags: Any = None): """Return SQLAlchemy clause for fetching businesses eligible for involuntary dissolution. Args: exclude_in_dissolution (bool): If True, exclude businesses already in dissolution. """ + eligibility_filters = eligibility_filters or InvoluntaryDissolutionService.EligibilityFilters() in_dissolution = ( exists().where( BatchProcessing.business_id == Business.id, @@ -121,14 +121,14 @@ def _get_businesses_eligible_query(eligibility_filters: EligibilityFilters = Eli Batch.batch_type == Batch.BatchType.INVOLUNTARY_DISSOLUTION ) ) - specific_filing_overdue = _has_specific_filing_overdue() < func.timezone('UTC', func.now()) + specific_filing_overdue = _has_specific_filing_overdue() < func.timezone("UTC", func.now()) no_transition_filed_after_restoration = func.coalesce((_has_no_transition_filed_after_restoration() - <= func.timezone('UTC', func.now())), False) + <= func.timezone("UTC", func.now())), False) query = db.session.query( Business, - specific_filing_overdue.label('ar_overdue'), - no_transition_filed_after_restoration.label('transition_overdue') + specific_filing_overdue.label("ar_overdue"), + no_transition_filed_after_restoration.label("transition_overdue") ).\ filter(not_(Business.admin_freeze.is_(True))).\ filter(Business.state == Business.State.ACTIVE).\ @@ -198,7 +198,7 @@ def _has_no_transition_filed_after_restoration(): Check if the business needs to file Transition but does not file it within 12 months after restoration. """ - new_act_date = func.date('2004-03-29 00:00:00+00:00') + new_act_date = func.date("2004-03-29 00:00:00+00:00") restoration_filing = aliased(Filing) transition_filing = aliased(Filing) @@ -262,7 +262,7 @@ def _is_limited_restored(): """ return and_( Business.restoration_expiry_date.isnot(None), - Business.restoration_expiry_date >= func.timezone('UTC', func.now()) + Business.restoration_expiry_date >= func.timezone("UTC", func.now()) ) @@ -273,26 +273,29 @@ def _is_xpro_from_nwpta(): """ return and_( Business.legal_type == Business.LegalTypes.EXTRA_PRO_A.value, - Business.jurisdiction == 'CA', + Business.jurisdiction == "CA", Business.foreign_jurisdiction_region.isnot(None), - Business.foreign_jurisdiction_region.in_(['AB', 'SK', 'MB']) + Business.foreign_jurisdiction_region.in_(["AB", "SK", "MB"]) ) -def _check_feature_flags_filter(flags: any = None): +def _check_feature_flags_filter(flags: Any = None): """Check eligibility for dissolution based on inclusion and exclusion of businesses.""" if flags is None: - op = type("flagType", (object,), {"is_on": lambda x,y: True, "value": lambda x,y: {}}) + op = type("flagType", (object,), {"is_on": lambda w,x,y=None,z=None: True, "value": lambda w,x,y=None,z=None: {}}) flags = op() + request_context = get_request_context() # Scenario 1: If the flag is off, proceed with the standard eligibility check. - if not flags.is_on('enable-involuntary-dissolution-filter'): + if not flags.is_on("enable-involuntary-dissolution-filter", + request_context.user, + request_context.account_id): return True # Continue with the usual logic # Get the dissolution filter data (handle if filter is None or empty) - involuntary_dissolution_filter = flags.value('involuntary-dissolution-filter') or {} + involuntary_dissolution_filter = flags.value("involuntary-dissolution-filter") or {} - include_accounts = involuntary_dissolution_filter.get('include-accounts', []) - exclude_accounts = involuntary_dissolution_filter.get('exclude-accounts', []) + include_accounts = involuntary_dissolution_filter.get("include-accounts", []) + exclude_accounts = involuntary_dissolution_filter.get("exclude-accounts", []) # Convert accounts to sets for efficient filtering include_entities = set(_get_filtered_entities(include_accounts)) if include_accounts else set() @@ -322,8 +325,8 @@ def _get_filtered_entities(accounts): entities = AccountService.get_affiliations(int(org_id)) for entity in entities: - identifier = entity.get('businessIdentifier') - if identifier and not (identifier.startswith('T') or identifier.startswith('NR')): + identifier = entity.get("businessIdentifier") + if identifier and not identifier.startswith(("T","NR")): filtered_entities.append(identifier) return filtered_entities diff --git a/python/common/business-registry-dissolution/src/dissolution_service/request_context.py b/python/common/business-registry-dissolution/src/dissolution_service/request_context.py new file mode 100644 index 0000000000..7ab8eb103b --- /dev/null +++ b/python/common/business-registry-dissolution/src/dissolution_service/request_context.py @@ -0,0 +1,58 @@ +# Copyright © 2025 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Helpers to build and access a per-request RequestContext. + +Copied from legal-api. +TODO: move this into common or flags package as part of #33537 +""" +from dataclasses import dataclass + +from flask import g, has_request_context, request + +from business_model.models import User + + +@dataclass(frozen=True) +class RequestContext: + account_id: str | None = None + user: User | None = None + + +def build_from_flask() -> RequestContext: + """Build a RequestContext from the active Flask request, if any.""" + if not has_request_context(): + return RequestContext() + + # Account header (configurable) + account_id = request.headers.get("Account-Id", None) + + # Token info and user + token_info = getattr(g, "jwt_oidc_token_info", None) + user = User.get_or_create_user_by_jwt(token_info) if token_info else None + + return RequestContext( + account_id=account_id, + user=user, + ) + + +def get_request_context() -> RequestContext: + """Get (or lazily create) the RequestContext for the current request.""" + if not has_request_context(): + return RequestContext() + rc = getattr(g, "request_context", None) + if rc is None: + rc = build_from_flask() + g.request_context = rc + return rc diff --git a/python/common/business-registry-dissolution/tests/__init__.py b/python/common/business-registry-dissolution/tests/__init__.py index d910c002eb..663c4d477b 100644 --- a/python/common/business-registry-dissolution/tests/__init__.py +++ b/python/common/business-registry-dissolution/tests/__init__.py @@ -12,32 +12,34 @@ # See the License for the specific language governing permissions and # limitations under the License. """This module holds general utility functions and helpers for the main package.""" -from datedelta import datedelta import base64 import uuid -from business_common.utils.datetime import datetime -from datetime import datetime as _datetime, timezone from contextlib import contextmanager +from datetime import UTC, timezone +from datetime import datetime as _datetime + +from datedelta import datedelta from freezegun import freeze_time +from sqlalchemy import exc +from business_common.utils.datetime import datetime from business_model.models import ( Batch, BatchProcessing, Business, - db, Filing, + db, ) - +from business_model.models.colin_event_id import ColinEventId from business_model.models.db import VersioningProxy - -EPOCH_DATETIME = datetime.from_date(_datetime(1970, 1, 1, tzinfo=timezone.utc)) -FROZEN_DATETIME = _datetime(2001, 8, 5, 7, 7, 58, 272362, tzinfo=timezone.utc) +EPOCH_DATETIME = datetime.from_date(_datetime(1970, 1, 1, tzinfo=UTC)) +FROZEN_DATETIME = _datetime(2001, 8, 5, 7, 7, 58, 272362, tzinfo=UTC) def factory_batch(batch_type=Batch.BatchType.INVOLUNTARY_DISSOLUTION, status=Batch.BatchStatus.HOLD, size=3, - notes=''): + notes=""): batch = Batch( batch_type=batch_type, status=status, @@ -54,7 +56,7 @@ def factory_batch_processing(batch_id, step=BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1, status=BatchProcessing.BatchProcessingStatus.PROCESSING, trigger_date=datetime.utcnow() + datedelta(days=42), - notes='' + notes="" ): batch_processing = BatchProcessing( batch_id=batch_id, @@ -83,14 +85,14 @@ def factory_business(identifier, last_ar_year = None if last_ar_date: last_ar_year = last_ar_date.year - business = Business(legal_name=f'legal_name-{identifier}', + business = Business(legal_name=f"legal_name-{identifier}", founding_date=founding_date, last_ar_date=last_ar_date, last_ar_year=last_ar_year, last_ledger_timestamp=EPOCH_DATETIME, # dissolution_date=EPOCH_DATETIME, identifier=identifier, - tax_id='BN123456789', + tax_id="BN123456789", fiscal_year_end_date=FROZEN_DATETIME, legal_type=entity_type, state=state, @@ -117,7 +119,7 @@ def factory_completed_filing(business, filing_sub_type=None): """Create a completed filing.""" if not payment_token: - payment_token = str(base64.urlsafe_b64encode(uuid.uuid4().bytes)).replace('=', '') + payment_token = str(base64.urlsafe_b64encode(uuid.uuid4().bytes)).replace("=", "") with freeze_time(filing_date): @@ -130,8 +132,8 @@ def factory_completed_filing(business, if filing_sub_type: filing._filing_sub_type = filing_sub_type - if (filing.filing_type == 'adminFreeze' or - (filing.filing_type == 'dissolution' and filing.filing_sub_type == 'involuntary')): + if (filing.filing_type == "adminFreeze" or + (filing.filing_type == "dissolution" and filing.filing_sub_type == "involuntary")): filing.hide_in_ledger = True filing.save() diff --git a/python/common/business-registry-dissolution/tests/conftest.py b/python/common/business-registry-dissolution/tests/conftest.py index d80c8b59a5..a1913e9b17 100644 --- a/python/common/business-registry-dissolution/tests/conftest.py +++ b/python/common/business-registry-dissolution/tests/conftest.py @@ -14,15 +14,16 @@ """Common setup and fixtures for the pytest suite used by this service.""" import contextlib +import business_model_migrations import pytest -from flask import Flask -from flask_jwt_oidc import JwtManager import sqlalchemy -from sqlalchemy import event, text +from flask import Flask from flask_migrate import Migrate, upgrade -from dissolution_service.config import TestConfig -import business_model_migrations +from sqlalchemy import event, text + from business_model.models import db as _db +from dissolution_service.config import TestConfig +from flask_jwt_oidc import JwtManager contextmanager = contextlib.contextmanager _jwt = JwtManager() @@ -110,14 +111,14 @@ def not_raises(exception): try: yield except exception: - raise pytest.fail(f'DID RAISE {exception}') + raise pytest.fail(f"DID RAISE {exception}") def setup_jwt_manager(app, jwt_manager): """Use flask app to configure the JWTManager to work for a particular Realm.""" def get_roles(a_dict): - return a_dict['realm_access']['roles'] # pragma: no cover - app.config['JWT_ROLE_CALLBACK'] = get_roles + return a_dict["realm_access"]["roles"] # pragma: no cover + app.config["JWT_ROLE_CALLBACK"] = get_roles jwt_manager.init_app(app) @@ -130,7 +131,7 @@ def create_app(): return app -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def app(): """Return a session-wide application configured in TEST mode.""" _app = create_app() @@ -138,7 +139,7 @@ def app(): return _app -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def app_ctx(event_loop): # def app_ctx(): """Return a session-wide application configured in TEST mode.""" @@ -153,23 +154,23 @@ def config(app): return app.config -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def app_request(): """Return a session-wide application configured in TEST mode.""" app = Flask(__name__) - app.config.from_object(Testing) + app.config.from_object(TestConfig) _db.init_app(app) return app -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def client(app): # pylint: disable=redefined-outer-name """Return a session-wide Flask test client.""" return app.test_client() -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def jwt(): """Return a session-wide jwt manager.""" return _jwt @@ -192,7 +193,7 @@ def db(app): # pylint: disable=redefined-outer-name, invalid-name app, _db, directory=business_model_migrations.__path__[0], - **{"dialect_name": "postgres"}, + dialect_name="postgres", ) upgrade() @@ -251,5 +252,5 @@ def run_around_tests(db): yield # run after each test db.session.rollback() - db.session.execute(text(f'TRUNCATE TABLE businesses CASCADE')) + db.session.execute(text(f"TRUNCATE TABLE businesses CASCADE")) db.session.commit() \ No newline at end of file diff --git a/python/common/business-registry-dissolution/tests/unit/test_involuntary_dissolution.py b/python/common/business-registry-dissolution/tests/unit/test_involuntary_dissolution.py index 77ba8e8a67..89e87cee3b 100644 --- a/python/common/business-registry-dissolution/tests/unit/test_involuntary_dissolution.py +++ b/python/common/business-registry-dissolution/tests/unit/test_involuntary_dissolution.py @@ -20,12 +20,11 @@ import pytest from datedelta import datedelta - from registry_schemas.example_data import FILING_HEADER, RESTORATION, TRANSITION_FILING_TEMPLATE +from business_common.utils.datetime import datetime from business_model.models import Batch, Business from dissolution_service import InvoluntaryDissolutionService -from business_common.utils.datetime import datetime from tests import ( factory_batch, factory_batch_processing, @@ -34,20 +33,19 @@ factory_pending_filing, ) - RESTORATION_FILING = copy.deepcopy(FILING_HEADER) -RESTORATION_FILING['filing']['restoration'] = RESTORATION +RESTORATION_FILING["filing"]["restoration"] = RESTORATION @pytest.mark.parametrize( - 'test_name, eligible', [ - ('TEST_INELIGIBLE', False), - ('TEST_ELIGIBLE', True) + "test_name, eligible", [ + ("TEST_INELIGIBLE", False), + ("TEST_ELIGIBLE", True) ] ) def test_check_business_eligibility(session, test_name, eligible): """Assert service returns check of business eligibility for involuntary dissolution.""" - identifier = 'BC7654321' + identifier = "BC7654321" business = factory_business(identifier=identifier, entity_type=Business.LegalTypes.COMP.value) if not eligible: business.no_dissolution = True @@ -64,14 +62,14 @@ def test_get_businesses_eligible_count(session): @pytest.mark.parametrize( - 'test_name, state, exclude', [ - ('TEST_ACTIVE', 'ACTIVE', False), - ('TEST_HISTORICAL', 'HISTORICAL', True) + "test_name, state, exclude", [ + ("TEST_ACTIVE", "ACTIVE", False), + ("TEST_HISTORICAL", "HISTORICAL", True) ] ) def test_get_businesses_eligible_query_active_business(session, test_name, state, exclude): """Assert service returns eligible business for active businesses.""" - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value, state=state) + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value, state=state) result = InvoluntaryDissolutionService._get_businesses_eligible_query().all() if exclude: assert not result @@ -81,25 +79,25 @@ def test_get_businesses_eligible_query_active_business(session, test_name, state @pytest.mark.parametrize( - 'test_name, legal_type, exclude', [ - ('TEST_BC', 'BC', False), - ('TEST_ULC', 'ULC', False), - ('TEST_CCC', 'CC', False), - ('TEST_BEN', 'BEN', False), - ('TEST_CONTINUE_IN', 'C', False), - ('TEST_ULC_CONTINUE_IN', 'CUL', False), - ('TEST_CCC_CONTINUE_IN', 'CCC', False), - ('TEST_BEN_CONTINUE_IN', 'CBEN', False), - ('TEST_XPRO', 'A', False), - ('TEST_LLC', 'LLC', False), - ('TEST_COOP', 'CP', True), - ('TEST_SP', 'SP', True), - ('TEST_GP', 'GP', True) + "test_name, legal_type, exclude", [ + ("TEST_BC", "BC", False), + ("TEST_ULC", "ULC", False), + ("TEST_CCC", "CC", False), + ("TEST_BEN", "BEN", False), + ("TEST_CONTINUE_IN", "C", False), + ("TEST_ULC_CONTINUE_IN", "CUL", False), + ("TEST_CCC_CONTINUE_IN", "CCC", False), + ("TEST_BEN_CONTINUE_IN", "CBEN", False), + ("TEST_XPRO", "A", False), + ("TEST_LLC", "LLC", False), + ("TEST_COOP", "CP", True), + ("TEST_SP", "SP", True), + ("TEST_GP", "GP", True) ] ) def test_get_businesses_eligible_query_eligible_type(session, test_name, legal_type, exclude): """Assert service returns eligible business for businesses with eligible types.""" - business = factory_business(identifier='BC1234567', entity_type=legal_type) + business = factory_business(identifier="BC1234567", entity_type=legal_type) result = InvoluntaryDissolutionService._get_businesses_eligible_query().all() if exclude: @@ -110,14 +108,14 @@ def test_get_businesses_eligible_query_eligible_type(session, test_name, legal_t @pytest.mark.parametrize( - 'test_name, no_dissolution, exclude', [ - ('TEST_NO_DISSOLUTION', True, True), - ('TEST_DISSOLUTION', False, False), + "test_name, no_dissolution, exclude", [ + ("TEST_NO_DISSOLUTION", True, True), + ("TEST_DISSOLUTION", False, False), ] ) def test_get_businesses_eligible_query_no_dissolution(session, test_name, no_dissolution, exclude): """Assert service returns eligible business for businesses with no_dissolution flag off.""" - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) business.no_dissolution = no_dissolution business.save() @@ -130,18 +128,18 @@ def test_get_businesses_eligible_query_no_dissolution(session, test_name, no_dis @pytest.mark.parametrize( - 'test_name, batch_status, batch_processing_status, exclude', [ - ('IN_DISSOLUTION', 'PROCESSING', 'PROCESSING', True), - ('IN_DISSOLUTION_BATCH_COMPLETE', 'COMPLETED', 'WITHDRAWN', False), - ('IN_DISSOLUTION_COMPLETED', 'PROCESSING', 'COMPLETED', False), - ('IN_DISSOLUTION_WITHDRAWN', 'PROCESSING', 'WITHDRAWN', False), - ('NOT_IN_DISSOLUTION', None, None, False), + "test_name, batch_status, batch_processing_status, exclude", [ + ("IN_DISSOLUTION", "PROCESSING", "PROCESSING", True), + ("IN_DISSOLUTION_BATCH_COMPLETE", "COMPLETED", "WITHDRAWN", False), + ("IN_DISSOLUTION_COMPLETED", "PROCESSING", "COMPLETED", False), + ("IN_DISSOLUTION_WITHDRAWN", "PROCESSING", "WITHDRAWN", False), + ("NOT_IN_DISSOLUTION", None, None, False), ] ) def test_get_businesses_eligible_query_in_dissolution(session, test_name, batch_status, batch_processing_status, exclude): """Assert service returns eligible business for businesses not already in dissolution.""" - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) - if test_name.startswith('IN_DISSOLUTION'): + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) + if test_name.startswith("IN_DISSOLUTION"): batch = factory_batch( batch_type = Batch.BatchType.INVOLUNTARY_DISSOLUTION, status = batch_status, @@ -162,28 +160,28 @@ def test_get_businesses_eligible_query_in_dissolution(session, test_name, batch_ @pytest.mark.parametrize( - 'test_name, exclude', [ - ('RECOGNITION_OVERDUE', False), - ('RESTORATION_OVERDUE', False), - ('AR_OVERDUE', False), - ('AR_OVERDUE_IN_LIQUIDATION', True), - ('NO_OVERDUE', True) + "test_name, exclude", [ + ("RECOGNITION_OVERDUE", False), + ("RESTORATION_OVERDUE", False), + ("AR_OVERDUE", False), + ("AR_OVERDUE_IN_LIQUIDATION", True), + ("NO_OVERDUE", True) ] ) def test_get_businesses_eligible_query_specific_filing_overdue(session, test_name, exclude): """Assert service returns eligible business including business which has specific filing overdue.""" - if test_name == 'RECOGNITION_OVERDUE': - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) - elif test_name == 'RESTORATION_OVERDUE': - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) + if test_name == "RECOGNITION_OVERDUE": + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) + elif test_name == "RESTORATION_OVERDUE": + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) effective_date = datetime.utcnow() - datedelta(years=3) - factory_completed_filing(business, RESTORATION_FILING, filing_type='restoration', filing_date=effective_date) - elif test_name.startswith('AR_OVERDUE'): + factory_completed_filing(business, RESTORATION_FILING, filing_type="restoration", filing_date=effective_date) + elif test_name.startswith("AR_OVERDUE"): last_ar_date = datetime.utcnow() - datedelta(years=3) - in_liquidation_date = datetime.utcnow() if test_name == 'AR_OVERDUE_IN_LIQUIDATION' else None - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value, last_ar_date=last_ar_date, in_liquidation_date=in_liquidation_date) + in_liquidation_date = datetime.utcnow() if test_name == "AR_OVERDUE_IN_LIQUIDATION" else None + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value, last_ar_date=last_ar_date, in_liquidation_date=in_liquidation_date) else: - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value, founding_date=datetime.utcnow()) + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value, founding_date=datetime.utcnow()) business.save() @@ -196,23 +194,23 @@ def test_get_businesses_eligible_query_specific_filing_overdue(session, test_nam @pytest.mark.parametrize( - 'test_name, exclude', [ - ('TRANSITION', True), - ('NO_NEED_TRANSITION_NEW_ACT', True), - ('NO_NEED_TRANSITION_1_YEAR', True), - ('MISSING_TRANSITION', False) + "test_name, exclude", [ + ("TRANSITION", True), + ("NO_NEED_TRANSITION_NEW_ACT", True), + ("NO_NEED_TRANSITION_1_YEAR", True), + ("MISSING_TRANSITION", False) ] ) def test_get_businesses_eligible_query_no_transition_filed(session, test_name, exclude): """Assert service returns eligible business excluding business which doesn't file transition.""" - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value, last_ar_date=datetime.utcnow()) - restoration_filing = factory_completed_filing(business, RESTORATION_FILING, filing_type='restoration') - if test_name == 'TRANSITION': - factory_completed_filing(business, TRANSITION_FILING_TEMPLATE, filing_type='transition') - elif test_name == 'NO_NEED_TRANSITION_NEW_ACT': + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value, last_ar_date=datetime.utcnow()) + restoration_filing = factory_completed_filing(business, RESTORATION_FILING, filing_type="restoration") + if test_name == "TRANSITION": + factory_completed_filing(business, TRANSITION_FILING_TEMPLATE, filing_type="transition") + elif test_name == "NO_NEED_TRANSITION_NEW_ACT": business.founding_date = datetime.utcnow() business.save() - elif test_name == 'NO_NEED_TRANSITION_1_YEAR': + elif test_name == "NO_NEED_TRANSITION_1_YEAR": restoration_filing.effective_date = datetime.utcnow() restoration_filing.save() @@ -225,15 +223,15 @@ def test_get_businesses_eligible_query_no_transition_filed(session, test_name, e @pytest.mark.parametrize( - 'test_name, exclude', [ - ('FED', True), - ('NO_FED', False) + "test_name, exclude", [ + ("FED", True), + ("NO_FED", False) ] ) def test_get_businesses_eligible_query_fed_filing(session, test_name, exclude): """Assert service returns eligible business excluding business which has future effective filings.""" - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) - if test_name == 'FED': + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) + if test_name == "FED": factory_pending_filing(business, RESTORATION_FILING) result = InvoluntaryDissolutionService._get_businesses_eligible_query().all() @@ -245,18 +243,18 @@ def test_get_businesses_eligible_query_fed_filing(session, test_name, exclude): @pytest.mark.parametrize( - 'test_name, exclude', [ - ('LIMITED_RESTORATION', True), - ('LIMITED_RESTORATION_EXPIRED', False), - ('NON_LIMITED_RESTORATION', False) + "test_name, exclude", [ + ("LIMITED_RESTORATION", True), + ("LIMITED_RESTORATION_EXPIRED", False), + ("NON_LIMITED_RESTORATION", False) ] ) def test_get_businesses_eligible_query_limited_restored(session, test_name, exclude): """Assert service returns eligible business excluding business which is in limited restoration status.""" - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) - if test_name == 'LIMITED_RESTORATION': + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) + if test_name == "LIMITED_RESTORATION": business.restoration_expiry_date = datetime.utcnow() + datedelta(years=1) - elif test_name == 'LIMITED_RESTORATION_EXPIRED': + elif test_name == "LIMITED_RESTORATION_EXPIRED": business.restoration_expiry_date = datetime.utcnow() + datedelta(years=-1) business.save() @@ -269,18 +267,18 @@ def test_get_businesses_eligible_query_limited_restored(session, test_name, excl @pytest.mark.parametrize( - 'test_name, jurisdiction, region, exclude', [ - ('XPRO_NWPTA', 'CA', 'AB', True), - ('XPRO_NON_NWPTA', 'CA', 'ON', False), - ('NON_XPRO', None, None, False) + "test_name, jurisdiction, region, exclude", [ + ("XPRO_NWPTA", "CA", "AB", True), + ("XPRO_NON_NWPTA", "CA", "ON", False), + ("NON_XPRO", None, None, False) ] ) def test_get_businesses_eligible_query_xpro_from_nwpta(session, test_name, jurisdiction, region, exclude): """Assert service returns eligible business excluding expro from NWPTA jurisdictions.""" - if test_name == 'NON_XPRO': - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) + if test_name == "NON_XPRO": + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) else: - business = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.EXTRA_PRO_A.value) + business = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.EXTRA_PRO_A.value) business.jurisdiction = jurisdiction business.foreign_jurisdiction_region = region business.save() @@ -294,14 +292,14 @@ def test_get_businesses_eligible_query_xpro_from_nwpta(session, test_name, juris @pytest.mark.parametrize( - 'test_name, admin_freeze, eligible', { - ('BUSINESS_NOT_ADMIN_FREEZE', False, True), - ('BUSINESS_ADMIN_FREEZE', True, False) + "test_name, admin_freeze, eligible", { + ("BUSINESS_NOT_ADMIN_FREEZE", False, True), + ("BUSINESS_ADMIN_FREEZE", True, False) } ) def test_exclude_admin_frozen_businesses(session, test_name, admin_freeze, eligible): """Assert service returns eligible business excluding admin frozen businesses""" - identifier = 'BC1234567' + identifier = "BC1234567" factory_business(identifier=identifier, admin_freeze=admin_freeze, entity_type=Business.LegalTypes.COMP.value) check_query = InvoluntaryDissolutionService._get_businesses_eligible_query().\ @@ -313,13 +311,13 @@ def test_exclude_admin_frozen_businesses(session, test_name, admin_freeze, eligi @pytest.mark.parametrize( - 'test_name, expected_order', [ - ('TEST_OVERDUE_ORDER', [ - ('BC1234567', True, True), # transition_overdue, earliest - ('BC3456789', True, True), # transition_overdue, next earliest - ('BC7654321', False, True), # transition_overdue, latest - ('BC9876543', True, False), # ar_overdue, earliest - ('BC2468101', True, False), # ar_overdue, latest + "test_name, expected_order", [ + ("TEST_OVERDUE_ORDER", [ + ("BC1234567", True, True), # transition_overdue, earliest + ("BC3456789", True, True), # transition_overdue, next earliest + ("BC7654321", False, True), # transition_overdue, latest + ("BC9876543", True, False), # ar_overdue, earliest + ("BC2468101", True, False), # ar_overdue, latest ]), ] ) @@ -329,41 +327,41 @@ def test_get_businesses_eligible_query_order(session, test_name, expected_order) newest based on relevant cutoff dates.""" # create business that will be ar_overdue with latest ar_cutoff - business_overdue5 = factory_business(identifier='BC2468101', entity_type=Business.LegalTypes.COMP.value) + business_overdue5 = factory_business(identifier="BC2468101", entity_type=Business.LegalTypes.COMP.value) business_overdue5.last_ar_date = datetime.utcnow() - datedelta(years=2, months=9) business_overdue5.save() # create business that will be ar_overdue with earliest ar_cutoff - business_overdue4 = factory_business(identifier='BC9876543', entity_type=Business.LegalTypes.COMP.value) + business_overdue4 = factory_business(identifier="BC9876543", entity_type=Business.LegalTypes.COMP.value) business_overdue4.last_ar_date = datetime.utcnow() - datedelta(years=3) business_overdue4.save() # create business that will be transition_overdue with latest restoration date - business_overdue2 = factory_business(identifier='BC7654321', entity_type=Business.LegalTypes.COMP.value) - restoration_filing2 = factory_completed_filing(business_overdue2, RESTORATION_FILING, filing_type='restoration') + business_overdue2 = factory_business(identifier="BC7654321", entity_type=Business.LegalTypes.COMP.value) + restoration_filing2 = factory_completed_filing(business_overdue2, RESTORATION_FILING, filing_type="restoration") restoration_filing2.effective_date = datetime.utcnow() - datedelta(years=2) restoration_filing2.save() business_overdue2.save() # create business that will be transition_overdue with earliest restoration date - business_overdue1 = factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.COMP.value) - restoration_filing1 = factory_completed_filing(business_overdue1, RESTORATION_FILING, filing_type='restoration') + business_overdue1 = factory_business(identifier="BC1234567", entity_type=Business.LegalTypes.COMP.value) + restoration_filing1 = factory_completed_filing(business_overdue1, RESTORATION_FILING, filing_type="restoration") restoration_filing1.effective_date = datetime.utcnow() - datedelta(years=3) restoration_filing1.save() business_overdue1.last_ar_date = datetime.utcnow() - datedelta(years=3) business_overdue1.save() # create business that will be transition_overdue - business_overdue3 = factory_business(identifier='BC3456789', entity_type=Business.LegalTypes.COMP.value) - restoration_filing3 = factory_completed_filing(business_overdue3, RESTORATION_FILING, filing_type='restoration') + business_overdue3 = factory_business(identifier="BC3456789", entity_type=Business.LegalTypes.COMP.value) + restoration_filing3 = factory_completed_filing(business_overdue3, RESTORATION_FILING, filing_type="restoration") restoration_filing3.effective_date = datetime.utcnow() - datedelta(years=2, months=6) restoration_filing3.save() business_overdue3.save() # create business that is neither ar_overdue nor transition_overdue - business_no_overdue = factory_business(identifier='BC1122334', entity_type=Business.LegalTypes.COMP.value) - factory_completed_filing(business_no_overdue, RESTORATION_FILING, filing_type='restoration') - factory_completed_filing(business_no_overdue, TRANSITION_FILING_TEMPLATE, filing_type='transition') + business_no_overdue = factory_business(identifier="BC1122334", entity_type=Business.LegalTypes.COMP.value) + factory_completed_filing(business_no_overdue, RESTORATION_FILING, filing_type="restoration") + factory_completed_filing(business_no_overdue, TRANSITION_FILING_TEMPLATE, filing_type="transition") business_no_overdue.last_ar_date = datetime.utcnow() business_no_overdue.save()