From 650c816a7b65057fe2c075c33d3d623fab1c1027 Mon Sep 17 00:00:00 2001 From: Trenton Holmes <797416+stumpylog@users.noreply.github.com> Date: Sat, 9 Sep 2023 09:08:55 -0700 Subject: [PATCH] Removes support for Python 3.8 and lower from the code base --- .github/workflows/ci.yml | 9 +- .pre-commit-config.yaml | 2 +- .python-version | 2 +- .ruff.toml | 2 +- CONTRIBUTING.md | 2 +- Pipfile | 1 - Pipfile.lock | 339 +++++++----------- docs/setup.md | 2 +- src/documents/barcodes.py | 16 +- src/documents/classifier.py | 7 +- src/documents/consumer.py | 3 +- src/documents/data_models.py | 3 +- src/documents/double_sided.py | 6 +- .../management/commands/document_consumer.py | 3 +- .../management/commands/document_exporter.py | 6 +- src/documents/parsers.py | 7 +- src/documents/serialisers.py | 8 +- src/documents/tasks.py | 3 +- src/documents/tests/test_api.py | 7 +- src/documents/tests/test_consumer.py | 7 +- src/documents/tests/test_document_model.py | 6 +- src/documents/tests/test_matchables.py | 2 +- ...est_migration_encrypted_webp_conversion.py | 2 +- .../tests/test_migration_webp_conversion.py | 2 +- src/documents/tests/utils.py | 14 +- src/documents/utils.py | 3 +- src/paperless/checks.py | 6 +- src/paperless/settings.py | 18 +- src/paperless/version.py | 3 +- src/paperless_mail/mail.py | 8 +- src/paperless_mail/parsers.py | 3 +- src/paperless_mail/tests/test_mail.py | 20 +- src/paperless_tesseract/tests/test_parser.py | 4 +- src/paperless_tika/tests/test_tika_parser.py | 6 +- 34 files changed, 195 insertions(+), 337 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 117273bcd..323bd1230 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,9 +17,8 @@ env: # This is the version of pipenv all the steps will use # If changing this, change Dockerfile DEFAULT_PIP_ENV_VERSION: "2023.9.8" - # This is the default version of Python to use in most steps - # If changing this, change Dockerfile - DEFAULT_PYTHON_VERSION: "3.9" + # This is the default version of Python to use in most steps which aren't specific + DEFAULT_PYTHON_VERSION: "3.10" jobs: pre-commit: @@ -105,7 +104,7 @@ jobs: - pre-commit strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11'] fail-fast: false steps: - @@ -283,7 +282,7 @@ jobs: # a tag # Otherwise forks would require a Docker Hub account and secrets setup run: | - if [[ ${{ github.repository_owner }} == "paperless-ngx" && ( ${{ github.ref_name }} == "main" || ${{ github.ref_name }} == "dev" || ${{ github.ref_name }} == "beta" || ${{ startsWith(github.ref, 'refs/tags/v') }} == "true" ) ]] ; then + if [[ ${{ github.repository_owner }} == "paperless-ngx" && ( ${{ github.ref_name }} == "dev" || ${{ github.ref_name }} == "beta" || ${{ startsWith(github.ref, 'refs/tags/v') }} == "true" ) ]] ; then echo "Enabling DockerHub image push" echo "enable=true" >> $GITHUB_OUTPUT else diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f271a0a09..f55c4afbe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,7 +41,7 @@ repos: hooks: - id: ruff - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.7.0 + rev: 23.9.0 hooks: - id: black # Dockerfile hooks diff --git a/.python-version b/.python-version index e29d80998..43077b246 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.8.17 +3.9.18 diff --git a/.ruff.toml b/.ruff.toml index 23b39089c..441781820 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -7,7 +7,7 @@ fix = true line-length = 88 respect-gitignore = true src = ["src"] -target-version = "py38" +target-version = "py39" format = "grouped" show-fixes = true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65220af25..c23fd635b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ If you want to implement something big: ## Python -Paperless supports python 3.8 and 3.9. We format Python code with [Black](https://github.com/psf/black). +Paperless supports python 3.9 - 3.11. We format Python code with [Black](https://github.com/psf/black). ## Branches diff --git a/Pipfile b/Pipfile index b934104bf..a9366fd50 100644 --- a/Pipfile +++ b/Pipfile @@ -87,7 +87,6 @@ types-redis = "*" types-tqdm = "*" types-Markdown = "*" types-Pygments = "*" -types-backports = "*" types-colorama = "*" types-psycopg2 = "*" types-setuptools = "*" diff --git a/Pipfile.lock b/Pipfile.lock index b1bd5a309..4d27f5c95 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a3c89ceea5672a9fc97836a0dfef8e3cc0dcdab411847bc7f3bfa574b0446f1a" + "sha256": "ac966c7a02e216e5198e13857f2701fd5e9b1c4dbb39ad151889f8a4d8cd8711" }, "pipfile-spec": 6, "requires": {}, @@ -46,28 +46,6 @@ "markers": "python_full_version <= '3.11.2'", "version": "==4.0.3" }, - "backports.zoneinfo": { - "hashes": [ - "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf", - "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328", - "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546", - "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6", - "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570", - "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9", - "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7", - "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987", - "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722", - "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582", - "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc", - "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b", - "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1", - "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08", - "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac", - "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2" - ], - "markers": "python_version < '3.9'", - "version": "==0.2.1" - }, "billiard": { "hashes": [ "sha256:0f50d6be051c6b2b75bfbc8bfd85af195c5739c281d3f5b86a5640c65563614a", @@ -746,14 +724,6 @@ ], "version": "==0.4.4" }, - "importlib-resources": { - "hashes": [ - "sha256:134832a506243891221b88b4ae1213327eea96ceb4e407a00d790bb0626f45cf", - "sha256:4359457e42708462b9626a04657c6208ad799ceb41e5c58c57ffa0e6a098a5d4" - ], - "markers": "python_version < '3.9'", - "version": "==6.0.1" - }, "inotify-simple": { "hashes": [ "sha256:8440ffe49c4ae81a8df57c1ae1eb4b6bfa7acb830099bfb3e305b383005cc128" @@ -1001,37 +971,34 @@ }, "numpy": { "hashes": [ - "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f", - "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61", - "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7", - "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400", - "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef", - "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2", - "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d", - "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc", - "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835", - "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706", - "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5", - "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4", - "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6", - "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463", - "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a", - "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f", - "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e", - "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e", - "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694", - "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8", - "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64", - "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d", - "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc", - "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254", - "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2", - "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1", - "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810", - "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9" + "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2", + "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55", + "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf", + "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01", + "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca", + "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901", + "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d", + "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4", + "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf", + "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380", + "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044", + "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545", + "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f", + "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f", + "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3", + "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364", + "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9", + "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418", + "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f", + "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295", + "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3", + "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187", + "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926", + "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357", + "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760" ], - "markers": "python_version >= '3.8'", - "version": "==1.24.4" + "markers": "python_version >= '3.9'", + "version": "==1.25.2" }, "ocrmypdf": { "hashes": [ @@ -1608,30 +1575,34 @@ }, "scipy": { "hashes": [ - "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415", - "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f", - "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd", - "sha256:1553b5dcddd64ba9a0d95355e63fe6c3fc303a8fd77c7bc91e77d61363f7433f", - "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d", - "sha256:1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601", - "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5", - "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88", - "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f", - "sha256:4b3f429188c66603a1a5c549fb414e4d3bdc2a24792e061ffbd607d3d75fd84e", - "sha256:4c0ff64b06b10e35215abce517252b375e580a6125fd5fdf6421b98efbefb2d2", - "sha256:51af417a000d2dbe1ec6c372dfe688e041a7084da4fdd350aeb139bd3fb55353", - "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35", - "sha256:79c8e5a6c6ffaf3a2262ef1be1e108a035cf4f05c14df56057b64acc5bebffb6", - "sha256:7ff7f37b1bf4417baca958d254e8e2875d0cc23aaadbe65b3d5b3077b0eb23ea", - "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35", - "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1", - "sha256:cd9f1027ff30d90618914a64ca9b1a77a431159df0e2a195d8a9e8a04c78abf9", - "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5", - "sha256:e7354fd7527a4b0377ce55f286805b34e8c54b91be865bac273f527e1b839019", - "sha256:fae8a7b898c42dffe3f7361c40d5952b6bf32d10c4569098d276b4c547905ee1" + "sha256:0f3261f14b767b316d7137c66cc4f33a80ea05841b9c87ad83a726205b901423", + "sha256:10eb6af2f751aa3424762948e5352f707b0dece77288206f227864ddf675aca0", + "sha256:1342ca385c673208f32472830c10110a9dcd053cf0c4b7d4cd7026d0335a6c1d", + "sha256:214cdf04bbae7a54784f8431f976704ed607c4bc69ba0d5d5d6a9df84374df76", + "sha256:2b997a5369e2d30c97995dcb29d638701f8000d04df01b8e947f206e5d0ac788", + "sha256:2c91cf049ffb5575917f2a01da1da082fd24ed48120d08a6e7297dfcac771dcd", + "sha256:3aeb87661de987f8ec56fa6950863994cd427209158255a389fc5aea51fa7055", + "sha256:4447ad057d7597476f9862ecbd9285bbf13ba9d73ce25acfa4e4b11c6801b4c9", + "sha256:542a757e2a6ec409e71df3d8fd20127afbbacb1c07990cb23c5870c13953d899", + "sha256:8d9886f44ef8c9e776cb7527fb01455bf4f4a46c455c4682edc2c2cc8cd78562", + "sha256:90d3b1364e751d8214e325c371f0ee0dd38419268bf4888b2ae1040a6b266b2a", + "sha256:95763fbda1206bec41157582bea482f50eb3702c85fffcf6d24394b071c0e87a", + "sha256:ac74b1512d38718fb6a491c439aa7b3605b96b1ed3be6599c17d49d6c60fca18", + "sha256:afdb0d983f6135d50770dd979df50bf1c7f58b5b33e0eb8cf5c73c70600eae1d", + "sha256:b0620240ef445b5ddde52460e6bc3483b7c9c750275369379e5f609a1050911c", + "sha256:b133f237bd8ba73bad51bc12eb4f2d84cbec999753bf25ba58235e9fc2096d80", + "sha256:b29318a5e39bd200ca4381d80b065cdf3076c7d7281c5e36569e99273867f61d", + "sha256:b8425fa963a32936c9773ee3ce44a765d8ff67eed5f4ac81dc1e4a819a238ee9", + "sha256:d2b813bfbe8dec6a75164523de650bad41f4405d35b0fa24c2c28ae07fcefb20", + "sha256:d690e1ca993c8f7ede6d22e5637541217fc6a4d3f78b3672a6fe454dbb7eb9a7", + "sha256:e367904a0fec76433bf3fbf3e85bf60dae8e9e585ffd21898ab1085a29a04d16", + "sha256:ea932570b1c2a30edafca922345854ff2cd20d43cd9123b6dacfdecebfc1a80b", + "sha256:f28f1f6cfeb48339c192efc6275749b2a25a7e49c4d8369a28b6591da02fbc9a", + "sha256:f73102f769ee06041a3aa26b5841359b1a93cc364ce45609657751795e8f4a4a", + "sha256:fa4909c6c20c3d91480533cddbc0e7c6d849e7d9ded692918c76ce5964997898" ], - "markers": "python_version < '3.12' and python_version >= '3.8'", - "version": "==1.10.1" + "markers": "python_version < '3.13' and python_version >= '3.9'", + "version": "==1.11.2" }, "setproctitle": { "hashes": [ @@ -2025,14 +1996,6 @@ "index": "pypi", "version": "==2.7.4" }, - "zipp": { - "hashes": [ - "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", - "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147" - ], - "markers": "python_version < '3.10'", - "version": "==3.16.2" - }, "zstandard": { "hashes": [ "sha256:0aad6090ac164a9d237d096c8af241b8dcd015524ac6dbec1330092dba151657", @@ -2132,10 +2095,10 @@ }, "autobahn": { "hashes": [ - "sha256:c5ef8ca7422015a1af774a883b8aef73d4954c9fcd182c9b5244e08e973f7c3a" + "sha256:ec9421c52a2103364d1ef0468036e6019ee84f71721e86b36fe19ad6966c1181" ], - "markers": "python_version >= '3.7'", - "version": "==23.1.2" + "markers": "python_version >= '3.9'", + "version": "==23.6.2" }, "automat": { "hashes": [ @@ -2154,32 +2117,12 @@ }, "black": { "hashes": [ - "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3", - "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb", - "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087", - "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320", - "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6", - "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3", - "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc", - "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f", - "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587", - "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91", - "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a", - "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad", - "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926", - "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9", - "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be", - "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd", - "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96", - "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491", - "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2", - "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a", - "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f", - "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995" + "sha256:3511c8a7e22ce653f89ae90dfddaf94f3bb7e2587a245246572d3b9c92adf066", + "sha256:9366c1f898981f09eb8da076716c02fd021f5a0e63581c66501d68a2e4eab844" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==23.7.0" + "version": "==23.9.0" }, "certifi": { "hashes": [ @@ -2503,11 +2446,11 @@ }, "faker": { "hashes": [ - "sha256:0c3a7cbaa6497dcc18819bfe31ae916d2180c31a3b1ea8907c948d94eb06955d", - "sha256:11f0d2a6632d212e8ab89fd9152a1b8db777816e42f3579f8c63c11e43cec873" + "sha256:7cf705758f6cc5dd31f628e323f306a6d881e9a8a103f1e32e5f30a4cad0974c", + "sha256:d79d5ea59f31e00fbb882546840a4adb2fd0bae99b103db1ba5869f176bc530b" ], "markers": "python_version >= '3.8'", - "version": "==19.4.0" + "version": "==19.6.0" }, "filelock": { "hashes": [ @@ -2736,37 +2679,34 @@ }, "numpy": { "hashes": [ - "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f", - "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61", - "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7", - "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400", - "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef", - "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2", - "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d", - "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc", - "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835", - "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706", - "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5", - "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4", - "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6", - "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463", - "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a", - "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f", - "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e", - "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e", - "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694", - "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8", - "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64", - "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d", - "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc", - "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254", - "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2", - "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1", - "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810", - "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9" + "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2", + "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55", + "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf", + "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01", + "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca", + "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901", + "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d", + "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4", + "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf", + "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380", + "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044", + "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545", + "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f", + "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f", + "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3", + "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364", + "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9", + "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418", + "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f", + "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295", + "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3", + "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187", + "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926", + "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357", + "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760" ], - "markers": "python_version >= '3.8'", - "version": "==1.24.4" + "markers": "python_version >= '3.9'", + "version": "==1.25.2" }, "packaging": { "hashes": [ @@ -2969,12 +2909,12 @@ }, "pytest-httpx": { "hashes": [ - "sha256:3a82797f3a9a14d51e8c6b7fa97524b68b847ee801109c062e696b4744f4431c", - "sha256:cefb7dcf66a4cb0601b0de05e576cca423b6081f3245e7912a4d84c58fa3eae8" + "sha256:193cecb57a005eb15288f68986f328d4c8d06c0b7c4ef1ce512e024cbb1d5961", + "sha256:259e6266cf3e04eb8fcc18dff262657ad96f6b8668dc2171fb353eaec5571889" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==0.22.0" + "markers": "python_version >= '3.9'", + "version": "==0.24.0" }, "pytest-rerunfailures": { "hashes": [ @@ -3011,13 +2951,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.2" }, - "pytz": { - "hashes": [ - "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", - "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7" - ], - "version": "==2023.3.post1" - }, "pywavelets": { "hashes": [ "sha256:030670a213ee8fefa56f6387b0c8e7d970c7f7ad6850dc048bd7c89364771b9b", @@ -3240,30 +3173,34 @@ }, "scipy": { "hashes": [ - "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415", - "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f", - "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd", - "sha256:1553b5dcddd64ba9a0d95355e63fe6c3fc303a8fd77c7bc91e77d61363f7433f", - "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d", - "sha256:1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601", - "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5", - "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88", - "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f", - "sha256:4b3f429188c66603a1a5c549fb414e4d3bdc2a24792e061ffbd607d3d75fd84e", - "sha256:4c0ff64b06b10e35215abce517252b375e580a6125fd5fdf6421b98efbefb2d2", - "sha256:51af417a000d2dbe1ec6c372dfe688e041a7084da4fdd350aeb139bd3fb55353", - "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35", - "sha256:79c8e5a6c6ffaf3a2262ef1be1e108a035cf4f05c14df56057b64acc5bebffb6", - "sha256:7ff7f37b1bf4417baca958d254e8e2875d0cc23aaadbe65b3d5b3077b0eb23ea", - "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35", - "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1", - "sha256:cd9f1027ff30d90618914a64ca9b1a77a431159df0e2a195d8a9e8a04c78abf9", - "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5", - "sha256:e7354fd7527a4b0377ce55f286805b34e8c54b91be865bac273f527e1b839019", - "sha256:fae8a7b898c42dffe3f7361c40d5952b6bf32d10c4569098d276b4c547905ee1" + "sha256:0f3261f14b767b316d7137c66cc4f33a80ea05841b9c87ad83a726205b901423", + "sha256:10eb6af2f751aa3424762948e5352f707b0dece77288206f227864ddf675aca0", + "sha256:1342ca385c673208f32472830c10110a9dcd053cf0c4b7d4cd7026d0335a6c1d", + "sha256:214cdf04bbae7a54784f8431f976704ed607c4bc69ba0d5d5d6a9df84374df76", + "sha256:2b997a5369e2d30c97995dcb29d638701f8000d04df01b8e947f206e5d0ac788", + "sha256:2c91cf049ffb5575917f2a01da1da082fd24ed48120d08a6e7297dfcac771dcd", + "sha256:3aeb87661de987f8ec56fa6950863994cd427209158255a389fc5aea51fa7055", + "sha256:4447ad057d7597476f9862ecbd9285bbf13ba9d73ce25acfa4e4b11c6801b4c9", + "sha256:542a757e2a6ec409e71df3d8fd20127afbbacb1c07990cb23c5870c13953d899", + "sha256:8d9886f44ef8c9e776cb7527fb01455bf4f4a46c455c4682edc2c2cc8cd78562", + "sha256:90d3b1364e751d8214e325c371f0ee0dd38419268bf4888b2ae1040a6b266b2a", + "sha256:95763fbda1206bec41157582bea482f50eb3702c85fffcf6d24394b071c0e87a", + "sha256:ac74b1512d38718fb6a491c439aa7b3605b96b1ed3be6599c17d49d6c60fca18", + "sha256:afdb0d983f6135d50770dd979df50bf1c7f58b5b33e0eb8cf5c73c70600eae1d", + "sha256:b0620240ef445b5ddde52460e6bc3483b7c9c750275369379e5f609a1050911c", + "sha256:b133f237bd8ba73bad51bc12eb4f2d84cbec999753bf25ba58235e9fc2096d80", + "sha256:b29318a5e39bd200ca4381d80b065cdf3076c7d7281c5e36569e99273867f61d", + "sha256:b8425fa963a32936c9773ee3ce44a765d8ff67eed5f4ac81dc1e4a819a238ee9", + "sha256:d2b813bfbe8dec6a75164523de650bad41f4405d35b0fa24c2c28ae07fcefb20", + "sha256:d690e1ca993c8f7ede6d22e5637541217fc6a4d3f78b3672a6fe454dbb7eb9a7", + "sha256:e367904a0fec76433bf3fbf3e85bf60dae8e9e585ffd21898ab1085a29a04d16", + "sha256:ea932570b1c2a30edafca922345854ff2cd20d43cd9123b6dacfdecebfc1a80b", + "sha256:f28f1f6cfeb48339c192efc6275749b2a25a7e49c4d8369a28b6591da02fbc9a", + "sha256:f73102f769ee06041a3aa26b5841359b1a93cc364ce45609657751795e8f4a4a", + "sha256:fa4909c6c20c3d91480533cddbc0e7c6d849e7d9ded692918c76ce5964997898" ], - "markers": "python_version < '3.12' and python_version >= '3.8'", - "version": "==1.10.1" + "markers": "python_version < '3.13' and python_version >= '3.9'", + "version": "==1.11.2" }, "service-identity": { "hashes": [ @@ -3394,7 +3331,7 @@ "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147" ], - "markers": "python_version < '3.10'", + "markers": "python_version >= '3.8'", "version": "==3.16.2" }, "zope-interface": { @@ -3443,28 +3380,6 @@ "markers": "python_version >= '3.7'", "version": "==3.7.2" }, - "backports.zoneinfo": { - "hashes": [ - "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf", - "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328", - "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546", - "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6", - "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570", - "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9", - "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7", - "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987", - "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722", - "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582", - "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc", - "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b", - "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1", - "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08", - "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac", - "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2" - ], - "markers": "python_version < '3.9'", - "version": "==0.2.1" - }, "celery-types": { "hashes": [ "sha256:4048d7c59d2ce26127d32c2799b776d1b23a3de699eb6e6e9df1b8136dfe950f", @@ -3788,14 +3703,6 @@ "markers": "python_version < '3.11'", "version": "==2.0.1" }, - "types-backports": { - "hashes": [ - "sha256:dafcd61848081503e738a7768872d1dd6c018401b4d2a1cfb608ea87ec9864b9", - "sha256:f4b7206c073df88d6200891e3d27506185fd60cda66fb289737b2fa92c0010cf" - ], - "index": "pypi", - "version": "==0.1.3" - }, "types-bleach": { "hashes": [ "sha256:2b8767eb407c286b7f02803678732e522e04db8d56cbc9f1270bee49627eae92", diff --git a/docs/setup.md b/docs/setup.md index 10f260b73..1bda90b5d 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -255,7 +255,7 @@ supported. 1. Install dependencies. Paperless requires the following packages. - - `python3` - 3.8 - 3.11 are supported + - `python3` - 3.9 - 3.11 are supported - `python3-pip` - `python3-dev` - `default-libmysqlclient-dev` for MariaDB diff --git a/src/documents/barcodes.py b/src/documents/barcodes.py index b64f531d8..89d8c2685 100644 --- a/src/documents/barcodes.py +++ b/src/documents/barcodes.py @@ -2,9 +2,7 @@ import logging import tempfile from dataclasses import dataclass from pathlib import Path -from typing import Dict from typing import Final -from typing import List from typing import Optional from django.conf import settings @@ -53,7 +51,7 @@ class BarcodeReader: self.file: Final[Path] = filepath self.mime: Final[str] = mime_type self.pdf_file: Path = self.file - self.barcodes: List[Barcode] = [] + self.barcodes: list[Barcode] = [] self.temp_dir: Optional[tempfile.TemporaryDirectory] = None if settings.CONSUMER_BARCODE_TIFF_SUPPORT: @@ -111,7 +109,7 @@ class BarcodeReader: return asn @staticmethod - def read_barcodes_zxing(image: Image) -> List[str]: + def read_barcodes_zxing(image: Image) -> list[str]: barcodes = [] import zxingcpp @@ -127,7 +125,7 @@ class BarcodeReader: return barcodes @staticmethod - def read_barcodes_pyzbar(image: Image) -> List[str]: + def read_barcodes_pyzbar(image: Image) -> list[str]: barcodes = [] from pyzbar import pyzbar @@ -209,7 +207,7 @@ class BarcodeReader: f"Exception during barcode scanning: {e}", ) - def get_separation_pages(self) -> Dict[int, bool]: + def get_separation_pages(self) -> dict[int, bool]: """ Search the parsed barcodes for separators and returns a dict of page numbers, which separate the file into new files, together with the @@ -228,7 +226,7 @@ class BarcodeReader: **{bc.page: True for bc in self.barcodes if bc.is_asn and bc.page != 0}, } - def separate_pages(self, pages_to_split_on: Dict[int, bool]) -> List[Path]: + def separate_pages(self, pages_to_split_on: dict[int, bool]) -> list[Path]: """ Separate the provided pdf file on the pages_to_split_on. The pages which are defined by the keys in page_numbers @@ -241,9 +239,9 @@ class BarcodeReader: fname = self.file.with_suffix("").name with Pdf.open(self.pdf_file) as input_pdf: # Start with an empty document - current_document: List[Page] = [] + current_document: list[Page] = [] # A list of documents, ie a list of lists of pages - documents: List[List[Page]] = [current_document] + documents: list[list[Page]] = [current_document] for idx, page in enumerate(input_pdf.pages): # Keep building the new PDF as long as it is not a diff --git a/src/documents/classifier.py b/src/documents/classifier.py index 5ed203934..5a69002cc 100644 --- a/src/documents/classifier.py +++ b/src/documents/classifier.py @@ -3,11 +3,10 @@ import os import pickle import re import warnings +from collections.abc import Iterator from datetime import datetime from hashlib import sha256 from pathlib import Path -from typing import Iterator -from typing import List from typing import Optional from django.conf import settings @@ -357,7 +356,7 @@ class DocumentClassifier: # Tokenize # This splits the content into tokens, roughly words - words: List[str] = word_tokenize( + words: list[str] = word_tokenize( content, language=settings.NLTK_LANGUAGE, ) @@ -404,7 +403,7 @@ class DocumentClassifier: else: return None - def predict_tags(self, content: str) -> List[int]: + def predict_tags(self, content: str) -> list[int]: from sklearn.utils.multiclass import type_of_target if self.tags_classifier: diff --git a/src/documents/consumer.py b/src/documents/consumer.py index a44de6eca..3f83e0f50 100644 --- a/src/documents/consumer.py +++ b/src/documents/consumer.py @@ -8,7 +8,6 @@ from pathlib import Path from subprocess import CompletedProcess from subprocess import run from typing import Optional -from typing import Type import magic from asgiref.sync import async_to_sync @@ -372,7 +371,7 @@ class Consumer(LoggingMixin): self.log.debug(f"Detected mime type: {mime_type}") # Based on the mime type, get the parser for that type - parser_class: Optional[Type[DocumentParser]] = get_parser_class_for_mime_type( + parser_class: Optional[type[DocumentParser]] = get_parser_class_for_mime_type( mime_type, ) if not parser_class: diff --git a/src/documents/data_models.py b/src/documents/data_models.py index f904743d4..d8995287f 100644 --- a/src/documents/data_models.py +++ b/src/documents/data_models.py @@ -2,7 +2,6 @@ import dataclasses import datetime import enum from pathlib import Path -from typing import List from typing import Optional import magic @@ -20,7 +19,7 @@ class DocumentMetadataOverrides: title: Optional[str] = None correspondent_id: Optional[int] = None document_type_id: Optional[int] = None - tag_ids: Optional[List[int]] = None + tag_ids: Optional[list[int]] = None created: Optional[datetime.datetime] = None asn: Optional[int] = None owner_id: Optional[int] = None diff --git a/src/documents/double_sided.py b/src/documents/double_sided.py index 4e6b8b7a3..8bfad3586 100644 --- a/src/documents/double_sided.py +++ b/src/documents/double_sided.py @@ -115,12 +115,10 @@ def collate(input_doc: ConsumableDocument) -> str: staging.unlink() else: - # In Python 3.9 move supports Path objects directly, - # but for now we have to be compatible with 3.8 - shutil.move(str(pdf_file), str(staging)) + shutil.move(pdf_file, staging) # update access to modification time so we know if the file # is outdated when another file gets uploaded - os.utime(str(staging), (dt.datetime.now().timestamp(),) * 2) + os.utime(staging, (dt.datetime.now().timestamp(),) * 2) logger.info( "Got scan with odd numbered pages of double-sided scan, moved it to %s", staging, diff --git a/src/documents/management/commands/document_consumer.py b/src/documents/management/commands/document_consumer.py index 220948a3d..085c180ae 100644 --- a/src/documents/management/commands/document_consumer.py +++ b/src/documents/management/commands/document_consumer.py @@ -8,7 +8,6 @@ from threading import Event from time import monotonic from time import sleep from typing import Final -from typing import Set from django.conf import settings from django.core.management.base import BaseCommand @@ -32,7 +31,7 @@ except ImportError: # pragma: nocover logger = logging.getLogger("paperless.management.consumer") -def _tags_from_path(filepath) -> Set[Tag]: +def _tags_from_path(filepath) -> set[Tag]: """ Walk up the directory tree from filepath to CONSUMPTION_DIR and get or create Tag IDs for every directory. diff --git a/src/documents/management/commands/document_exporter.py b/src/documents/management/commands/document_exporter.py index 9484d86bb..ebadafa9e 100644 --- a/src/documents/management/commands/document_exporter.py +++ b/src/documents/management/commands/document_exporter.py @@ -5,8 +5,6 @@ import shutil import tempfile import time from pathlib import Path -from typing import List -from typing import Set import tqdm from django.conf import settings @@ -138,8 +136,8 @@ class Command(BaseCommand): BaseCommand.__init__(self, *args, **kwargs) self.target: Path = None self.split_manifest = False - self.files_in_export_dir: Set[Path] = set() - self.exported_files: List[Path] = [] + self.files_in_export_dir: set[Path] = set() + self.exported_files: list[Path] = [] self.compare_checksums = False self.use_filename_format = False self.use_folder_prefix = False diff --git a/src/documents/parsers.py b/src/documents/parsers.py index bedc8bdef..2e6b17cb5 100644 --- a/src/documents/parsers.py +++ b/src/documents/parsers.py @@ -6,12 +6,11 @@ import re import shutil import subprocess import tempfile +from collections.abc import Iterator from functools import lru_cache from pathlib import Path -from typing import Iterator -from typing import Match +from re import Match from typing import Optional -from typing import Set from django.conf import settings from django.utils import timezone @@ -90,7 +89,7 @@ def is_file_ext_supported(ext: str) -> bool: return False -def get_supported_file_extensions() -> Set[str]: +def get_supported_file_extensions() -> set[str]: extensions = set() for response in document_consumer_declaration.send(None): parser_declaration = response[1] diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index d3a1ba866..09c1c1a69 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -1,14 +1,10 @@ import datetime import math import re +import zoneinfo -from celery import states - -try: - import zoneinfo -except ImportError: - from backports import zoneinfo import magic +from celery import states from django.conf import settings from django.contrib.auth.models import Group from django.contrib.auth.models import User diff --git a/src/documents/tasks.py b/src/documents/tasks.py index 0f16b717c..6ecd30b42 100644 --- a/src/documents/tasks.py +++ b/src/documents/tasks.py @@ -3,7 +3,6 @@ import logging import shutil import uuid from typing import Optional -from typing import Type import tqdm from asgiref.sync import async_to_sync @@ -216,7 +215,7 @@ def update_document_archive_file(document_id): mime_type = document.mime_type - parser_class: Type[DocumentParser] = get_parser_class_for_mime_type(mime_type) + parser_class: type[DocumentParser] = get_parser_class_for_mime_type(mime_type) if not parser_class: logger.error( diff --git a/src/documents/tests/test_api.py b/src/documents/tests/test_api.py index 88180d4d8..ee2afc51d 100644 --- a/src/documents/tests/test_api.py +++ b/src/documents/tests/test_api.py @@ -7,18 +7,13 @@ import tempfile import urllib.request import uuid import zipfile +import zoneinfo from datetime import timedelta from pathlib import Path from unittest import mock from unittest.mock import MagicMock import celery - -try: - import zoneinfo -except ImportError: - from backports import zoneinfo - import pytest from dateutil.relativedelta import relativedelta from django.conf import settings diff --git a/src/documents/tests/test_consumer.py b/src/documents/tests/test_consumer.py index 8d5f220fc..70227b0db 100644 --- a/src/documents/tests/test_consumer.py +++ b/src/documents/tests/test_consumer.py @@ -5,16 +5,11 @@ import shutil import stat import tempfile import uuid +import zoneinfo from unittest import mock from unittest.mock import MagicMock from dateutil import tz - -try: - import zoneinfo -except ImportError: - from backports import zoneinfo - from django.conf import settings from django.test import TestCase from django.test import override_settings diff --git a/src/documents/tests/test_document_model.py b/src/documents/tests/test_document_model.py index ad357e30a..68539e5dd 100644 --- a/src/documents/tests/test_document_model.py +++ b/src/documents/tests/test_document_model.py @@ -1,13 +1,9 @@ import shutil import tempfile +import zoneinfo from pathlib import Path from unittest import mock -try: - import zoneinfo -except ImportError: - from backports import zoneinfo - from django.test import TestCase from django.test import override_settings from django.utils import timezone diff --git a/src/documents/tests/test_matchables.py b/src/documents/tests/test_matchables.py index 4dac4f58f..34bdffe95 100644 --- a/src/documents/tests/test_matchables.py +++ b/src/documents/tests/test_matchables.py @@ -1,7 +1,7 @@ import shutil import tempfile +from collections.abc import Iterable from random import randint -from typing import Iterable from django.contrib.admin.models import LogEntry from django.contrib.auth.models import User diff --git a/src/documents/tests/test_migration_encrypted_webp_conversion.py b/src/documents/tests/test_migration_encrypted_webp_conversion.py index d8c5ddd52..879f4b0df 100644 --- a/src/documents/tests/test_migration_encrypted_webp_conversion.py +++ b/src/documents/tests/test_migration_encrypted_webp_conversion.py @@ -1,9 +1,9 @@ import importlib import shutil import tempfile +from collections.abc import Iterable from pathlib import Path from typing import Callable -from typing import Iterable from typing import Union from unittest import mock diff --git a/src/documents/tests/test_migration_webp_conversion.py b/src/documents/tests/test_migration_webp_conversion.py index 18367cbe6..97af07361 100644 --- a/src/documents/tests/test_migration_webp_conversion.py +++ b/src/documents/tests/test_migration_webp_conversion.py @@ -1,9 +1,9 @@ import importlib import shutil import tempfile +from collections.abc import Iterable from pathlib import Path from typing import Callable -from typing import Iterable from typing import Union from unittest import mock diff --git a/src/documents/tests/utils.py b/src/documents/tests/utils.py index 2eced0c4f..b1e9c0523 100644 --- a/src/documents/tests/utils.py +++ b/src/documents/tests/utils.py @@ -3,14 +3,12 @@ import tempfile import time import warnings from collections import namedtuple +from collections.abc import Iterator from contextlib import contextmanager from os import PathLike from pathlib import Path from typing import Any from typing import Callable -from typing import Iterator -from typing import List -from typing import Tuple from typing import Union from unittest import mock @@ -88,10 +86,10 @@ def paperless_environment(): def util_call_with_backoff( method_or_callable: Callable, - args: Union[List, Tuple], + args: Union[list, tuple], *, skip_on_50x_err=True, -) -> Tuple[bool, Any]: +) -> tuple[bool, Any]: """ For whatever reason, the images started during the test pipeline like to segfault sometimes, crash and otherwise fail randomly, when run with the @@ -219,7 +217,7 @@ class DocumentConsumeDelayMixin: def get_last_consume_delay_call_args( self, - ) -> Tuple[ConsumableDocument, DocumentMetadataOverrides]: + ) -> tuple[ConsumableDocument, DocumentMetadataOverrides]: """ Returns the most recent arguments to the async task """ @@ -233,7 +231,7 @@ class DocumentConsumeDelayMixin: def get_all_consume_delay_call_args( self, - ) -> Iterator[Tuple[ConsumableDocument, DocumentMetadataOverrides]]: + ) -> Iterator[tuple[ConsumableDocument, DocumentMetadataOverrides]]: """ Iterates over all calls to the async task and returns the arguments """ @@ -246,7 +244,7 @@ class DocumentConsumeDelayMixin: def get_specific_consume_delay_call_args( self, index: int, - ) -> Iterator[Tuple[ConsumableDocument, DocumentMetadataOverrides]]: + ) -> Iterator[tuple[ConsumableDocument, DocumentMetadataOverrides]]: """ Returns the arguments of a specific call to the async task """ diff --git a/src/documents/utils.py b/src/documents/utils.py index 45496fc9b..b84c9b53c 100644 --- a/src/documents/utils.py +++ b/src/documents/utils.py @@ -1,14 +1,13 @@ import shutil from os import utime from pathlib import Path -from typing import Tuple from typing import Union def _coerce_to_path( source: Union[Path, str], dest: Union[Path, str], -) -> Tuple[Path, Path]: +) -> tuple[Path, Path]: return Path(source).resolve(), Path(dest).resolve() diff --git a/src/paperless/checks.py b/src/paperless/checks.py index d3009d036..2b78eb4fa 100644 --- a/src/paperless/checks.py +++ b/src/paperless/checks.py @@ -155,10 +155,8 @@ def settings_values_check(app_configs, **kwargs): """ Validates the user provided timezone is a valid timezone """ - try: - import zoneinfo - except ImportError: # pragma: nocover - from backports import zoneinfo + import zoneinfo + msgs = [] if settings.TIME_ZONE not in zoneinfo.available_timezones(): msgs.append( diff --git a/src/paperless/settings.py b/src/paperless/settings.py index 7a636f7c1..6d25a53cc 100644 --- a/src/paperless/settings.py +++ b/src/paperless/settings.py @@ -7,12 +7,8 @@ import re import tempfile from os import PathLike from pathlib import Path -from typing import Dict from typing import Final -from typing import List from typing import Optional -from typing import Set -from typing import Tuple from typing import Union from urllib.parse import urlparse @@ -85,9 +81,9 @@ def __get_path( def __get_list( key: str, - default: Optional[List[str]] = None, + default: Optional[list[str]] = None, sep: str = ",", -) -> List[str]: +) -> list[str]: """ Return a list of elements from the environment, as separated by the given string, or the default if the key does not exist @@ -100,7 +96,7 @@ def __get_list( return [] -def _parse_redis_url(env_redis: Optional[str]) -> Tuple[str]: +def _parse_redis_url(env_redis: Optional[str]) -> tuple[str]: """ Gets the Redis information from the environment or a default and handles converting from incompatible django_channels and celery formats. @@ -138,7 +134,7 @@ def _parse_redis_url(env_redis: Optional[str]) -> Tuple[str]: return (env_redis, env_redis) -def _parse_beat_schedule() -> Dict: +def _parse_beat_schedule() -> dict: """ Configures the scheduled tasks, according to default or environment variables. Task expiration is configured so the task will @@ -492,7 +488,7 @@ EMAIL_CERTIFICATE_FILE = __get_path("PAPERLESS_EMAIL_CERTIFICATE_FILE") ############################################################################### # Database # ############################################################################### -def _parse_db_settings() -> Dict: +def _parse_db_settings() -> dict: databases = { "default": { "ENGINE": "django.db.backends.sqlite3", @@ -928,7 +924,7 @@ if TIKA_ENABLED: def _parse_ignore_dates( env_ignore: str, date_order: str = DATE_ORDER, -) -> Set[datetime.datetime]: +) -> set[datetime.datetime]: """ If the PAPERLESS_IGNORE_DATES environment variable is set, parse the user provided string(s) into dates @@ -957,7 +953,7 @@ def _parse_ignore_dates( # List dates that should be ignored when trying to parse date from document text -IGNORE_DATES: Set[datetime.date] = set() +IGNORE_DATES: set[datetime.date] = set() if os.getenv("PAPERLESS_IGNORE_DATES") is not None: IGNORE_DATES = _parse_ignore_dates(os.getenv("PAPERLESS_IGNORE_DATES")) diff --git a/src/paperless/version.py b/src/paperless/version.py index 1147d9ca8..a0e292948 100644 --- a/src/paperless/version.py +++ b/src/paperless/version.py @@ -1,7 +1,6 @@ from typing import Final -from typing import Tuple -__version__: Final[Tuple[int, int, int]] = (1, 17, 4) +__version__: Final[tuple[int, int, int]] = (1, 17, 4) # Version string like X.Y.Z __full_version_str__: Final[str] = ".".join(map(str, __version__)) # Version string like X.Y diff --git a/src/paperless_mail/mail.py b/src/paperless_mail/mail.py index 58b84c5ba..e0b584a8c 100644 --- a/src/paperless_mail/mail.py +++ b/src/paperless_mail/mail.py @@ -8,8 +8,6 @@ import traceback from datetime import date from datetime import timedelta from fnmatch import fnmatch -from typing import Dict -from typing import List from typing import Union import magic @@ -80,7 +78,7 @@ class BaseMailAction: read mails when the action is to mark mails as read). """ - def get_criteria(self) -> Union[Dict, LogicOperator]: + def get_criteria(self) -> Union[dict, LogicOperator]: """ Returns filtering criteria/query for this mail action. """ @@ -232,7 +230,7 @@ def mailbox_login(mailbox: MailBox, account: MailAccount): @shared_task def apply_mail_action( - result: List[str], + result: list[str], rule_id: int, message_uid: str, message_subject: str, @@ -319,7 +317,7 @@ def error_callback( def queue_consumption_tasks( *, - consume_tasks: List[Signature], + consume_tasks: list[Signature], rule: MailRule, message: MailMessage, ): diff --git a/src/paperless_mail/parsers.py b/src/paperless_mail/parsers.py index b1a0f75d7..bcfdd5b3d 100644 --- a/src/paperless_mail/parsers.py +++ b/src/paperless_mail/parsers.py @@ -1,7 +1,6 @@ import re from html import escape from pathlib import Path -from typing import List import httpx from bleach import clean @@ -355,7 +354,7 @@ class MailDocumentParser(DocumentParser): def generate_pdf_from_html( self, orig_html: str, - attachments: List[MailAttachment], + attachments: list[MailAttachment], ) -> Path: """ Generates a PDF file based on the HTML and attachments of the email diff --git a/src/paperless_mail/tests/test_mail.py b/src/paperless_mail/tests/test_mail.py index d7f543def..38585d9f2 100644 --- a/src/paperless_mail/tests/test_mail.py +++ b/src/paperless_mail/tests/test_mail.py @@ -3,8 +3,7 @@ import email.contentmanager import random import uuid from collections import namedtuple -from typing import ContextManager -from typing import List +from contextlib import AbstractContextManager from typing import Optional from typing import Union from unittest import mock @@ -53,8 +52,8 @@ class BogusFolderManager: class BogusClient: def __init__(self, messages): - self.messages: List[MailMessage] = messages - self.capabilities: List[str] = [] + self.messages: list[MailMessage] = messages + self.capabilities: list[str] = [] def __enter__(self): return self @@ -78,7 +77,7 @@ class BogusClient: MailMessage.flags.fget.cache_clear() -class BogusMailBox(ContextManager): +class BogusMailBox(AbstractContextManager): # Common values so tests don't need to remember an accepted login USERNAME: str = "admin" ASCII_PASSWORD: str = "secret" @@ -88,8 +87,8 @@ class BogusMailBox(ContextManager): ACCESS_TOKEN = "ea7e075cd3acf2c54c48e600398d5d5a" def __init__(self): - self.messages: List[MailMessage] = [] - self.messages_spam: List[MailMessage] = [] + self.messages: list[MailMessage] = [] + self.messages_spam: list[MailMessage] = [] self.folder = BogusFolderManager() self.client = BogusClient(self.messages) self._host = "" @@ -221,11 +220,11 @@ class TestMail( def create_message( self, - attachments: Union[int, List[_AttachmentDef]] = 1, + attachments: Union[int, list[_AttachmentDef]] = 1, body: str = "", subject: str = "the subject", from_: str = "noone@mail.com", - to: Optional[List[str]] = None, + to: Optional[list[str]] = None, seen: bool = False, flagged: bool = False, processed: bool = False, @@ -1056,6 +1055,7 @@ class TestMail( ], ) + @pytest.mark.flaky(reruns=4) def test_filters(self): account = MailAccount.objects.create( name="test3", @@ -1203,7 +1203,7 @@ class TestMail( self.assertEqual(len(self.bogus_mailbox.fetch("UNSEEN", False)), 0) self.assertEqual(len(self.bogus_mailbox.messages), 3) - def assert_queue_consumption_tasks_call_args(self, expected_call_args: List): + def assert_queue_consumption_tasks_call_args(self, expected_call_args: list): """ Verifies that queue_consumption_tasks has been called with the expected arguments. diff --git a/src/paperless_tesseract/tests/test_parser.py b/src/paperless_tesseract/tests/test_parser.py index 606453904..6a60ac3b7 100644 --- a/src/paperless_tesseract/tests/test_parser.py +++ b/src/paperless_tesseract/tests/test_parser.py @@ -2,8 +2,8 @@ import os import shutil import tempfile import uuid +from contextlib import AbstractContextManager from pathlib import Path -from typing import ContextManager from unittest import mock from django.test import TestCase @@ -29,7 +29,7 @@ def fake_convert(input_file, output_file, **kwargs): f2.write(line.strip()) -class FakeImageFile(ContextManager): +class FakeImageFile(AbstractContextManager): def __init__(self, fname): self.fname = fname diff --git a/src/paperless_tika/tests/test_tika_parser.py b/src/paperless_tika/tests/test_tika_parser.py index 4f64afc04..f693aa4e7 100644 --- a/src/paperless_tika/tests/test_tika_parser.py +++ b/src/paperless_tika/tests/test_tika_parser.py @@ -1,13 +1,9 @@ import datetime import os +import zoneinfo from pathlib import Path from unittest import mock -try: - import zoneinfo -except ImportError: - from backports import zoneinfo - from django.test import TestCase from django.test import override_settings from httpx import Request