From 551d8d995b5ba13a1e3ecf16586933bdead75d3c Mon Sep 17 00:00:00 2001 From: Tianyi Zheng Date: Mon, 3 Jun 2024 16:25:09 -0700 Subject: [PATCH] Add black and flake8 (#174) * Update black Update black from 19.10b0 to 24.4.2. black had been broken due to an ImportError (see https://github.com/psf/black/issues/2964). * Add black to pre-commit * Add black to GitHub Actions * Add flake8 to pre-commit * Update requirements.txt using Pipfile Ran `pipenv requirements --exclude-markers > requirements.txt` to update requirements.txt with correct dependencies and versions from Pipfile. I did this primarily to update the black version (because the previous version was broken with an ImportError), and I might as well update the rest of the dependencies as well. * Add flags to black for GitHub Actions Add the --check and --diff flags to black within GitHub Actions workflows so that the workflows fail if files need formatting. Without these flags, black will "format" the files and exit without error, which doesn't actually write to the files during workflows. * Add flags to flake8 and black for pre-commit Add flags to flake8 and black for pre-commit based on existing flags in GitHub Actions workflows. This includes selecting for specific flake8 errors and adjusting the max line length. These existing configs are extremely limited, so they should be broadened to more errors and/or a more widely accepted max line length. Also ran black on the entire codebase to satisfy the GitHub workflows. * Fix typo in black option flag * Fix formatting errors --- .github/workflows/autotest.yml | 3 +- .github/workflows/tests-on-push.yml | 4 +- .pre-commit-config.yaml | 20 + Pipfile | 4 +- Pipfile.lock | 667 +++++++++++++--------------- pittapi/__init__.py | 1 + pittapi/course.py | 41 +- pittapi/lab.py | 10 +- pittapi/laundry.py | 6 +- pittapi/library.py | 8 +- pittapi/news.py | 4 +- pittapi/people.py | 5 +- pittapi/shuttle.py | 8 +- pittapi/sports.py | 54 ++- pittapi/textbook.py | 51 +-- requirements.txt | 65 +-- setup.py | 72 ++- tests/__init__.py | 2 +- tests/course_test.py | 126 +++--- tests/dining_test.py | 54 ++- tests/laundry_test.py | 24 +- tests/library_test.py | 11 +- tests/mocks/course_mocks.py | 114 ++--- tests/news_test.py | 1 + tests/people_test.py | 36 +- tests/shuttle_test.py | 18 +- tests/sports_test.py | 112 ++--- tests/status_test.py | 8 +- tests/textbook_test.py | 159 +++---- 29 files changed, 743 insertions(+), 945 deletions(-) diff --git a/.github/workflows/autotest.yml b/.github/workflows/autotest.yml index 69bc922..ab9d8af 100644 --- a/.github/workflows/autotest.yml +++ b/.github/workflows/autotest.yml @@ -10,7 +10,6 @@ jobs: run-test-suite: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - name: Set up Python 3.12 @@ -28,6 +27,8 @@ jobs: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Format with black + run: black --line-length=127 --check --diff . - name: Run all tests with pytest run: pytest --cov=pittapi tests/ --ignore=tests/lab_test.py diff --git a/.github/workflows/tests-on-push.yml b/.github/workflows/tests-on-push.yml index 2a709bc..fe001ba 100644 --- a/.github/workflows/tests-on-push.yml +++ b/.github/workflows/tests-on-push.yml @@ -1,4 +1,3 @@ - name: Run Tests On Push on: @@ -12,7 +11,6 @@ permissions: jobs: build-and-test: - runs-on: ubuntu-latest steps: @@ -32,6 +30,8 @@ jobs: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Format with black + run: black --line-length=127 --check --diff . - name: Test with pytest run: pytest --cov=pittapi tests/ --ignore=tests/lab_test.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5b818df..eefe48d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,3 +5,23 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - id: check-yaml + +# https://flake8.pycqa.org/en/latest/user/using-hooks.html +- repo: https://github.com/pycqa/flake8 + rev: 7.0.0 + hooks: + - id: flake8 + # GitHub editor is 127 chars wide, see workflows in .github/ + args: [ + "--select=E9,F63,F7,F82", + "--max-line-length=127" + ] + +# https://black.readthedocs.io/en/stable/integrations/source_version_control.html +- repo: https://github.com/psf/black-pre-commit-mirror + rev: 24.4.2 + hooks: + - id: black + language_version: python3.12 + # GitHub editor is 127 chars wide, see workflows in .github/ + args: ["--line-length=127"] diff --git a/Pipfile b/Pipfile index 65b36ca..ff3b9ba 100644 --- a/Pipfile +++ b/Pipfile @@ -15,7 +15,7 @@ nose-cov = "*" nose-timer = "*" typing = "*" virtualenv = "*" -black = "==19.10b0" +black = "*" sphinx = "*" requests-html = "*" parse = "*" @@ -23,7 +23,7 @@ pre-commit = "*" pytest = "*" pytest-cov = "==4.1.0" pytest-xdist = "*" - +flake8 = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 84e31a7..73445bc 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0d579c7fc20400702619998a4d384bef984c5635449400a86b95c12e6776a464" + "sha256": "8409c697f4a2b9fc75428ef13a63318292b16b99a86b6805fe5747c3d20a8910" }, "pipfile-spec": 6, "requires": { @@ -31,21 +31,13 @@ ], "version": "==1.4.4" }, - "attrs": { - "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" - ], - "markers": "python_version >= '3.7'", - "version": "==23.2.0" - }, "babel": { "hashes": [ - "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", - "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" + "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", + "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413" ], - "markers": "python_version >= '3.7'", - "version": "==2.14.0" + "markers": "python_version >= '3.8'", + "version": "==2.15.0" }, "beautifulsoup4": { "hashes": [ @@ -58,12 +50,32 @@ }, "black": { "hashes": [ - "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b", - "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539" + "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474", + "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1", + "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0", + "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8", + "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96", + "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1", + "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04", + "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021", + "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94", + "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d", + "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c", + "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7", + "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c", + "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc", + "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7", + "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d", + "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c", + "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741", + "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce", + "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb", + "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063", + "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e" ], "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==19.10b0" + "markers": "python_version >= '3.8'", + "version": "==24.4.2" }, "bs4": { "hashes": [ @@ -277,34 +289,43 @@ }, "docutils": { "hashes": [ - "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", - "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b" + "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", + "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2" ], - "markers": "python_version >= '3.7'", - "version": "==0.20.1" + "markers": "python_version >= '3.9'", + "version": "==0.21.2" }, "execnet": { "hashes": [ - "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", - "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af" + "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", + "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==2.1.1" }, "fake-useragent": { "hashes": [ - "sha256:1ee651ebd17fa2442abe4393f00e311769051765cd20de23cc50dc771db89540", - "sha256:c2adf4c536f9b74053e1161374398cdd78d28762062db9b741639b2133da0016" + "sha256:57415096557c8a4e23b62a375c21c55af5fd4ba30549227f562d2c4f5b60e3b3", + "sha256:6387269f5a2196b5ba7ed8935852f75486845a1c95c50e72460e6a8e762f5c49" ], - "version": "==1.5.0" + "version": "==1.5.1" }, "filelock": { "hashes": [ - "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e", - "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c" + "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f", + "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a" ], "markers": "python_version >= '3.8'", - "version": "==3.13.1" + "version": "==3.14.0" + }, + "flake8": { + "hashes": [ + "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", + "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.1'", + "version": "==7.0.0" }, "gevent": { "hashes": [ @@ -427,19 +448,19 @@ }, "identify": { "hashes": [ - "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791", - "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e" + "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa", + "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d" ], "markers": "python_version >= '3.8'", - "version": "==2.5.35" + "version": "==2.5.36" }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "imagesize": { "hashes": [ @@ -451,11 +472,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792", - "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100" + "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", + "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2" ], "markers": "python_version >= '3.8'", - "version": "==7.0.2" + "version": "==7.1.0" }, "iniconfig": { "hashes": [ @@ -467,96 +488,160 @@ }, "jinja2": { "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", - "version": "==3.1.3" + "version": "==3.1.4" }, "lxml": { "hashes": [ - "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01", - "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f", - "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1", - "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431", - "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8", - "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623", - "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a", - "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1", - "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6", - "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67", - "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890", - "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372", - "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c", - "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb", - "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df", - "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84", - "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6", - "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45", - "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936", - "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca", - "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897", - "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a", - "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d", - "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14", - "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912", - "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354", - "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f", - "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c", - "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d", - "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862", - "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969", - "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e", - "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8", - "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e", - "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa", - "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45", - "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a", - "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147", - "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3", - "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3", - "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324", - "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3", - "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33", - "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f", - "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f", - "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764", - "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1", - "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114", - "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581", - "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d", - "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae", - "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da", - "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2", - "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e", - "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda", - "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5", - "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa", - "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1", - "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e", - "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7", - "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1", - "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95", - "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93", - "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5", - "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b", - "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05", - "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5", - "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f", - "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7", - "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8", - "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea", - "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa", - "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd", - "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b", - "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e", - "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4", - "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204", - "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a" + "sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3", + "sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a", + "sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0", + "sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b", + "sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f", + "sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6", + "sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73", + "sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d", + "sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad", + "sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b", + "sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a", + "sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5", + "sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab", + "sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316", + "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6", + "sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df", + "sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca", + "sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264", + "sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8", + "sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f", + "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b", + "sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3", + "sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5", + "sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed", + "sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab", + "sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5", + "sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726", + "sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d", + "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632", + "sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706", + "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8", + "sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472", + "sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835", + "sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf", + "sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db", + "sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d", + "sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545", + "sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9", + "sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be", + "sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe", + "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905", + "sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438", + "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db", + "sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776", + "sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c", + "sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed", + "sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd", + "sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484", + "sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d", + "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6", + "sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30", + "sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182", + "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61", + "sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425", + "sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb", + "sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1", + "sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511", + "sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e", + "sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207", + "sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b", + "sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585", + "sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56", + "sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391", + "sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85", + "sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147", + "sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18", + "sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1", + "sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa", + "sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48", + "sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3", + "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184", + "sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67", + "sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7", + "sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34", + "sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706", + "sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8", + "sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c", + "sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115", + "sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009", + "sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466", + "sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526", + "sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d", + "sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525", + "sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14", + "sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3", + "sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0", + "sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b", + "sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1", + "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f", + "sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf", + "sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf", + "sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0", + "sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b", + "sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff", + "sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88", + "sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2", + "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40", + "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716", + "sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2", + "sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2", + "sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a", + "sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734", + "sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87", + "sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48", + "sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36", + "sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b", + "sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07", + "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c", + "sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573", + "sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001", + "sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9", + "sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3", + "sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce", + "sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3", + "sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04", + "sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927", + "sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083", + "sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d", + "sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32", + "sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9", + "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f", + "sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2", + "sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c", + "sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d", + "sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393", + "sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8", + "sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6", + "sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66", + "sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5", + "sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97", + "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196", + "sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836", + "sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae", + "sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297", + "sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421", + "sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6", + "sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981", + "sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30", + "sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30", + "sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f", + "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324", + "sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==5.1.0" + "version": "==5.2.2" }, "markupsafe": { "hashes": [ @@ -624,6 +709,22 @@ "markers": "python_version >= '3.7'", "version": "==2.1.5" }, + "mccabe": { + "hashes": [ + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + ], + "markers": "python_version >= '3.6'", + "version": "==0.7.0" + }, + "mypy-extensions": { + "hashes": [ + "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", + "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.0" + }, "nodeenv": { "hashes": [ "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2", @@ -681,28 +782,36 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.2.2" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "pre-commit": { "hashes": [ - "sha256:ba637c2d7a670c10daedc059f5c49b5bd0aadbccfcd7ec15592cf9665117532c", - "sha256:c3ef34f463045c88658c5b99f38c1e297abdcc0ff13f98d3370055fbbfabc67e" + "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", + "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==3.6.2" + "version": "==3.7.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", + "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67" + ], + "markers": "python_version >= '3.8'", + "version": "==2.11.1" }, "pyee": { "hashes": [ @@ -712,13 +821,21 @@ "markers": "python_version >= '3.8'", "version": "==11.1.0" }, + "pyflakes": { + "hashes": [ + "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", + "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" + ], + "markers": "python_version >= '3.8'", + "version": "==3.2.0" + }, "pygments": { "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" + "markers": "python_version >= '3.8'", + "version": "==2.18.0" }, "pyppeteer": { "hashes": [ @@ -737,12 +854,12 @@ }, "pytest": { "hashes": [ - "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7", - "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044" + "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd", + "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.1.1" + "version": "==8.2.1" }, "pytest-cov": { "hashes": [ @@ -755,12 +872,12 @@ }, "pytest-xdist": { "hashes": [ - "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a", - "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24" + "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", + "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.5.0" + "markers": "python_version >= '3.8'", + "version": "==3.6.1" }, "pyyaml": { "hashes": [ @@ -819,113 +936,14 @@ "markers": "python_version >= '3.6'", "version": "==6.0.1" }, - "regex": { - "hashes": [ - "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5", - "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770", - "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc", - "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105", - "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d", - "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b", - "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9", - "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630", - "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6", - "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c", - "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482", - "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6", - "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a", - "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80", - "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5", - "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1", - "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f", - "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf", - "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb", - "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2", - "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347", - "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20", - "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060", - "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5", - "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73", - "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f", - "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d", - "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3", - "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae", - "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4", - "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2", - "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457", - "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c", - "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4", - "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87", - "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0", - "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704", - "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f", - "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f", - "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b", - "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5", - "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923", - "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715", - "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c", - "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca", - "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1", - "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756", - "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360", - "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc", - "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445", - "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e", - "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4", - "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a", - "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8", - "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53", - "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697", - "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf", - "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a", - "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415", - "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f", - "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9", - "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400", - "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d", - "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392", - "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb", - "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd", - "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861", - "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232", - "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95", - "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7", - "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39", - "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887", - "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5", - "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39", - "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb", - "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586", - "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97", - "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423", - "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69", - "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7", - "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1", - "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7", - "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5", - "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8", - "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91", - "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590", - "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe", - "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c", - "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64", - "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd", - "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa", - "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31", - "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988" - ], - "markers": "python_version >= '3.7'", - "version": "==2023.12.25" - }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289", + "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.2" }, "requests-html": { "hashes": [ @@ -947,11 +965,11 @@ }, "setuptools": { "hashes": [ - "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e", - "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c" + "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4", + "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0" ], "markers": "python_version >= '3.8'", - "version": "==69.2.0" + "version": "==70.0.0" }, "snowballstemmer": { "hashes": [ @@ -970,12 +988,12 @@ }, "sphinx": { "hashes": [ - "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560", - "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5" + "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3", + "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.2.6" + "version": "==7.3.7" }, "sphinxcontrib-applehelp": { "hashes": [ @@ -1025,68 +1043,13 @@ "markers": "python_version >= '3.9'", "version": "==1.1.10" }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, "tqdm": { "hashes": [ - "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9", - "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531" + "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644", + "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb" ], "markers": "python_version >= '3.7'", - "version": "==4.66.2" - }, - "typed-ast": { - "hashes": [ - "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10", - "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede", - "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e", - "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c", - "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d", - "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8", - "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e", - "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5", - "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155", - "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4", - "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba", - "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5", - "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a", - "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b", - "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311", - "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769", - "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686", - "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d", - "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2", - "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814", - "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9", - "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b", - "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b", - "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4", - "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd", - "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18", - "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa", - "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6", - "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee", - "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88", - "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4", - "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431", - "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04", - "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d", - "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02", - "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8", - "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437", - "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274", - "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f", - "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a", - "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2" - ], - "markers": "python_version >= '3.6'", - "version": "==1.5.5" + "version": "==4.66.4" }, "typing": { "hashes": [ @@ -1099,11 +1062,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", - "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], "markers": "python_version >= '3.8'", - "version": "==4.10.0" + "version": "==4.11.0" }, "urllib3": { "hashes": [ @@ -1115,12 +1078,12 @@ }, "virtualenv": { "hashes": [ - "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a", - "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197" + "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c", + "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==20.25.1" + "version": "==20.26.2" }, "w3lib": { "hashes": [ @@ -1207,11 +1170,11 @@ }, "zipp": { "hashes": [ - "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", - "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715" + "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059", + "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e" ], "markers": "python_version >= '3.8'", - "version": "==3.18.1" + "version": "==3.18.2" }, "zope.event": { "hashes": [ @@ -1223,45 +1186,39 @@ }, "zope.interface": { "hashes": [ - "sha256:02adbab560683c4eca3789cc0ac487dcc5f5a81cc48695ec247f00803cafe2fe", - "sha256:14e02a6fc1772b458ebb6be1c276528b362041217b9ca37e52ecea2cbdce9fac", - "sha256:25e0af9663eeac6b61b231b43c52293c2cb7f0c232d914bdcbfd3e3bd5c182ad", - "sha256:2606955a06c6852a6cff4abeca38346ed01e83f11e960caa9a821b3626a4467b", - "sha256:396f5c94654301819a7f3a702c5830f0ea7468d7b154d124ceac823e2419d000", - "sha256:3b240883fb43160574f8f738e6d09ddbdbf8fa3e8cea051603d9edfd947d9328", - "sha256:3b6c62813c63c543a06394a636978b22dffa8c5410affc9331ce6cdb5bfa8565", - "sha256:4ae9793f114cee5c464cc0b821ae4d36e1eba961542c6086f391a61aee167b6f", - "sha256:4bce517b85f5debe07b186fc7102b332676760f2e0c92b7185dd49c138734b70", - "sha256:4d45d2ba8195850e3e829f1f0016066a122bfa362cc9dc212527fc3d51369037", - "sha256:4dd374927c00764fcd6fe1046bea243ebdf403fba97a937493ae4be2c8912c2b", - "sha256:506f5410b36e5ba494136d9fa04c548eaf1a0d9c442b0b0e7a0944db7620e0ab", - "sha256:59f7374769b326a217d0b2366f1c176a45a4ff21e8f7cebb3b4a3537077eff85", - "sha256:5ee9789a20b0081dc469f65ff6c5007e67a940d5541419ca03ef20c6213dd099", - "sha256:6fc711acc4a1c702ca931fdbf7bf7c86f2a27d564c85c4964772dadf0e3c52f5", - "sha256:75d2ec3d9b401df759b87bc9e19d1b24db73083147089b43ae748aefa63067ef", - "sha256:76e0531d86523be7a46e15d379b0e975a9db84316617c0efe4af8338dc45b80c", - "sha256:8af82afc5998e1f307d5e72712526dba07403c73a9e287d906a8aa2b1f2e33dd", - "sha256:8f5d2c39f3283e461de3655e03faf10e4742bb87387113f787a7724f32db1e48", - "sha256:97785604824981ec8c81850dd25c8071d5ce04717a34296eeac771231fbdd5cd", - "sha256:a3046e8ab29b590d723821d0785598e0b2e32b636a0272a38409be43e3ae0550", - "sha256:abb0b3f2cb606981c7432f690db23506b1db5899620ad274e29dbbbdd740e797", - "sha256:ac7c2046d907e3b4e2605a130d162b1b783c170292a11216479bb1deb7cadebe", - "sha256:af27b3fe5b6bf9cd01b8e1c5ddea0a0d0a1b8c37dc1c7452f1e90bf817539c6d", - "sha256:b386b8b9d2b6a5e1e4eadd4e62335571244cb9193b7328c2b6e38b64cfda4f0e", - "sha256:b66335bbdbb4c004c25ae01cc4a54fd199afbc1fd164233813c6d3c2293bb7e1", - "sha256:d54f66c511ea01b9ef1d1a57420a93fbb9d48a08ec239f7d9c581092033156d0", - "sha256:de125151a53ecdb39df3cb3deb9951ed834dd6a110a9e795d985b10bb6db4532", - "sha256:de7916380abaef4bb4891740879b1afcba2045aee51799dfd6d6ca9bdc71f35f", - "sha256:e2fefad268ff5c5b314794e27e359e48aeb9c8bb2cbb5748a071757a56f6bb8f", - "sha256:e7b2bed4eea047a949296e618552d3fed00632dc1b795ee430289bdd0e3717f3", - "sha256:e87698e2fea5ca2f0a99dff0a64ce8110ea857b640de536c76d92aaa2a91ff3a", - "sha256:ede888382882f07b9e4cd942255921ffd9f2901684198b88e247c7eabd27a000", - "sha256:f444de0565db46d26c9fa931ca14f497900a295bd5eba480fc3fad25af8c763e", - "sha256:fa994e8937e8ccc7e87395b7b35092818905cf27c651e3ff3e7f29729f5ce3ce", - "sha256:febceb04ee7dd2aef08c2ff3d6f8a07de3052fc90137c507b0ede3ea80c21440" + "sha256:065f8ff0e034e43b8da05ffed308a9e3311720a2b13b83724f26a8dd6709964d", + "sha256:0940b3b44b6cc0375ea0da5fefee05a9abe8bb53594a3a6e4aafb9f99dc5de8d", + "sha256:15fa208d7a802c0dd3e9d4d5336619a37efd57f2d2ce830d9f9d5843a2b7daba", + "sha256:16f73c42f10f761051157332943ee1f7cf973cc1c78a50d1960c313a211cca4a", + "sha256:18f4061c3456c61557e9d7068e435f5db164b38f15f3d9bd995ff185c6db2c62", + "sha256:1e0678885d07e865047e15be3ebe5c87903cc7f5ca5edfd0045d1c7b43f7fe9d", + "sha256:297ee171f40f8f18665bb75f576df7d1ddce19f3e6696ef6acb930dcbfbf693f", + "sha256:36234d3b8211d053c42684666c2a04eb1a35e0cec6bc3e54586bb60fb0be3b17", + "sha256:3a00983c5c793b17b829020e11032dabab023c4e0ef12f134b90df802ae5adf2", + "sha256:3ca89624d0eabc7ce4f299c6d621531cb8b0ebac3bb4f9ebf2d057477602e1b8", + "sha256:45fb6fe8b5852564e63d6705a7904530a7c886056e6e9aaf938dc5e2bc637097", + "sha256:52901ff6d75a4332457610cbd2883f39b386c5bebe0745ecf78e3fe22cfdd0d9", + "sha256:563a7192a5baf8d9b189dc598c3555e695e00fdce3eafb88b30d6d3df986fcc5", + "sha256:68b13ac49becfaba5b77359559812daac0c5c4b3c0d43cdb293a2dec8db95c24", + "sha256:799743a342249c9b9529abd1115a3f81754800e75dea254b58efdd2984009798", + "sha256:7c18218451823ca9b5131ceaacf655fe9dd4e592ebf848cb0a65fe8428bbf604", + "sha256:8140cf2665c5a07adc285bc859fdda67cfbd7edd62480dfca2211f4798502b54", + "sha256:a430d2cc52aef2af0dc45866852730fbc93463cf8cdeb179e8ee04440e0955c4", + "sha256:a45a7990d143acc37faa905d4a528f5923a5dd30f46536977d8061d10a895b09", + "sha256:aaa1f8967c3f272de80c4bec4b1379f97cd29006323f50558bd2f780a4f637ef", + "sha256:ada5ac54ac7d34bb33423da40b7f3edfc54c6b9623ac9daac7f456dbf25173ba", + "sha256:bf9fa875a9bae5318f24b0d9ab9e2c8a23bccad2979e9e4305eed8119bbe3195", + "sha256:cd3ab863a4e7d888728c949ba052a649664dea156bdd7140eb9269bbe6e33205", + "sha256:d91698257850ca5f523a5513a69775e6fb7c18129311e118996f8e9b463d11b0", + "sha256:dcefd4012593ee410ebf5728ee98f61b3401f0563c5068e760aa2b7720ca68a0", + "sha256:de6c1dad571276768fd6bc92999e8d942151552662a9048e3384cac05b148985", + "sha256:de6eaa0b7df493904d24050dcdc3db6589bd94f7e49caab57971fe47a669b3ea", + "sha256:e7d200aef16e577682dd54a79ff5f4f897a9807722b54bd8a9bca404679c609d", + "sha256:e9961413091e3c9d5c3ed671757049cc6153280f39a154a0b633608efcfdec6b", + "sha256:ec57dec41c0c8b723dd70da1864d50908c689e1c9cf43f32e9b04c0992e5d93d" ], "markers": "python_version >= '3.7'", - "version": "==6.2" + "version": "==6.4.post1" } }, "develop": {} diff --git a/pittapi/__init__.py b/pittapi/__init__.py index da4a95d..9b83b5f 100644 --- a/pittapi/__init__.py +++ b/pittapi/__init__.py @@ -16,6 +16,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ + import requests from requests.packages.urllib3.exceptions import InsecureRequestWarning diff --git a/pittapi/course.py b/pittapi/course.py index 0aa74d5..d5ab43c 100644 --- a/pittapi/course.py +++ b/pittapi/course.py @@ -34,6 +34,7 @@ TERM_REGEX = "2\d\d[147]" VALID_TERMS = re.compile(TERM_REGEX) + class Instructor(NamedTuple): name: str email: Optional[str] = None @@ -91,6 +92,7 @@ class Course(NamedTuple): course_id: str course_title: str + class CourseDetails(NamedTuple): course: Course course_description: Optional[str] = None @@ -100,6 +102,7 @@ class CourseDetails(NamedTuple): attributes: List[Attribute] = None sections: Optional[List[Section]] = None + class Subject(NamedTuple): subject_code: str courses: Dict[str, Course] @@ -128,9 +131,7 @@ def get_subject_courses(subject: str) -> Subject: return Subject(subject_code=subject, courses=courses) -def get_course_details( - term: Union[str, int], subject: str, course: Union[str, int] -) -> CourseDetails: +def get_course_details(term: Union[str, int], subject: str, course: Union[str, int]) -> CourseDetails: term = _validate_term(term) subject = _validate_subject(subject) course = _validate_course(course) @@ -144,11 +145,7 @@ def get_course_details( credit_range = (json_response["units_minimum"], json_response["units_maximum"]) requisites = None - if ( - "offerings" in json_response - and len(json_response["offerings"]) != 0 - and "req_group" in json_response["offerings"][0] - ): + if "offerings" in json_response and len(json_response["offerings"]) != 0 and "req_group" in json_response["offerings"][0]: requisites = json_response["offerings"][0]["req_group"] components = None @@ -184,15 +181,10 @@ def get_course_details( status = section["enrl_stat_descr"] instructors = None - if ( - len(section["instructors"]) != 0 - and section["instructors"][0] != "To be Announced" - ): + if len(section["instructors"]) != 0 and section["instructors"][0] != "To be Announced": instructors = [] for instructor in section["instructors"]: - instructors.append( - Instructor(name=instructor["name"], email=instructor["email"]) - ) + instructors.append(Instructor(name=instructor["name"], email=instructor["email"])) meetings = None if len(section["meetings"]) != 0: @@ -223,12 +215,7 @@ def get_course_details( ) return CourseDetails( - course=Course( - subject_code=subject, - course_number=course, - course_id=internal_course_id, - course_title=course_title - ), + course=Course(subject_code=subject, course_number=course, course_id=internal_course_id, course_title=course_title), course_description=course_description, credit_range=credit_range, requisites=requisites, @@ -238,9 +225,7 @@ def get_course_details( ) -def get_section_details( - term: Union[str, int], class_number: Union[str, int] -) -> Section: +def get_section_details(term: Union[str, int], class_number: Union[str, int]) -> Section: term = _validate_term(term) json_response = _get_section_details(term, class_number) @@ -265,9 +250,7 @@ def get_section_details( date_range = meeting["date_range"].split(" - ") instructors = None - if len(meeting["instructors"]) != 0 and meeting["instructors"][0][ - "name" - ] not in ["To be Announced", "-"]: + if len(meeting["instructors"]) != 0 and meeting["instructors"][0]["name"] not in ["To be Announced", "-"]: instructors = [] for instructor in meeting["instructors"]: name = instructor["name"] @@ -328,9 +311,7 @@ def _validate_term(term: Union[str, int]) -> str: """Validates that the term entered follows the pattern that Pitt does for term codes.""" if VALID_TERMS.match(str(term)): return str(term) - raise ValueError( - "Term entered isn't a valid Pitt term, must match regex " + TERM_REGEX - ) + raise ValueError("Term entered isn't a valid Pitt term, must match regex " + TERM_REGEX) def _validate_subject(subject: str) -> str: diff --git a/pittapi/lab.py b/pittapi/lab.py index b95fe93..c30b5e2 100644 --- a/pittapi/lab.py +++ b/pittapi/lab.py @@ -48,6 +48,7 @@ class Lab(NamedTuple): linux: int """ + def _fetch_labs(): """Fetches dictionary of status of all labs.""" labs = {} @@ -80,12 +81,5 @@ def get_status(): if key["name"] in labs: total = key["total"] in_use = key["active"] - statuses.append( - { - "location": key["name"], - "isOpen": labs[key["name"]], - "total": total, - "in_use": in_use - } - ) + statuses.append({"location": key["name"], "isOpen": labs[key["name"]], "total": total, "in_use": in_use}) return statuses diff --git a/pittapi/laundry.py b/pittapi/laundry.py index bea5207..c63c32f 100644 --- a/pittapi/laundry.py +++ b/pittapi/laundry.py @@ -23,9 +23,7 @@ from bs4 import BeautifulSoup -BASE_URL = ( - "https://www.laundryview.com/api/currentRoomData?school_desc_key=197&location={}" -) +BASE_URL = "https://www.laundryview.com/api/currentRoomData?school_desc_key=197&location={}" LOCATION_LOOKUP = { "TOWERS": "2430136", @@ -63,7 +61,7 @@ def get_status_simple(building_name: str) -> Dict[str, str]: -> SUTH_WEST """ laundry_info = _get_laundry_info(building_name) - freeWashers, freeDryers, totalWashers, totalDryers = 0,0,0,0 + freeWashers, freeDryers, totalWashers, totalDryers = 0, 0, 0, 0 for obj in laundry_info["objects"]: if obj["type"] == "washFL": diff --git a/pittapi/library.py b/pittapi/library.py index 2bd6a7d..4c75aeb 100644 --- a/pittapi/library.py +++ b/pittapi/library.py @@ -119,15 +119,11 @@ def _extract_documents(documents: List[Dict[str, Any]]) -> List[Dict[str, Any]]: return new_docs -def _extract_facets( - facet_fields: List[Dict[str, Any]] -) -> Dict[str, List[Dict[str, Any]]]: +def _extract_facets(facet_fields: List[Dict[str, Any]]) -> Dict[str, List[Dict[str, Any]]]: facets = {} # type: Dict[str,List[Dict[str,Any]]] for facet in facet_fields: facets[facet["display_name"]] = [] for count in facet["counts"]: - facets[facet["display_name"]].append( - {"value": count["value"], "count": count["count"]} - ) + facets[facet["display_name"]].append({"value": count["value"], "count": count["count"]}) return facets diff --git a/pittapi/news.py b/pittapi/news.py index 333d47e..ab4c957 100644 --- a/pittapi/news.py +++ b/pittapi/news.py @@ -37,9 +37,7 @@ def _load_n_items(feed: str, max_news_items: int): request_objs = [] for i in range(int(math.ceil(max_news_items / 10))): payload["start"] = i * 10 - request_objs.append( - grequests.get("https://m.pitt.edu/news/index.json", params=payload) - ) + request_objs.append(grequests.get("https://m.pitt.edu/news/index.json", params=payload)) responses = grequests.imap(request_objs) diff --git a/pittapi/people.py b/pittapi/people.py index 6009dd9..b009beb 100644 --- a/pittapi/people.py +++ b/pittapi/people.py @@ -16,6 +16,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ + from requests_html import HTMLSession from typing import List, Dict from parse import compile @@ -66,7 +67,7 @@ def get_person(query: str) -> List[Dict[str, str]]: session = HTMLSession() resp = session.post(PEOPLE_SEARCH_URL, data=payload) if resp.text.__contains__("Too many people matched your criteria."): - return [{"ERROR":"Too many people matched your criteria."}] # Return an error + return [{"ERROR": "Too many people matched your criteria."}] # Return an error elements = resp.html.xpath("/html/div/section") result = [] for entry in elements: @@ -75,5 +76,5 @@ def get_person(query: str) -> List[Dict[str, str]]: _parse_segments(person, segments) result.append(person) if result == []: - return [{"ERROR":"No one found."}] # Return an error + return [{"ERROR": "No one found."}] # Return an error return result diff --git a/pittapi/shuttle.py b/pittapi/shuttle.py index 8fcf8c7..faeefe4 100644 --- a/pittapi/shuttle.py +++ b/pittapi/shuttle.py @@ -33,9 +33,7 @@ def get_map_vehicle_points(api_key: str = "8882812681") -> Dict[str, Any]: return response.json() -def get_route_stop_arrivals( - api_key: str = "8882812681", times_per_stop: int = 1 -) -> Dict[str, Any]: +def get_route_stop_arrivals(api_key: str = "8882812681", times_per_stop: int = 1) -> Dict[str, Any]: """Return stop arrival times for all vehicles.""" payload = {"ApiKey": api_key, "TimesPerStopString": times_per_stop} response = sess.get( @@ -45,9 +43,7 @@ def get_route_stop_arrivals( return response.json() -def get_vehicle_route_stop_estimates( - vehicle_id: str, quantity: int = 2 -) -> Dict[str, Any]: +def get_vehicle_route_stop_estimates(vehicle_id: str, quantity: int = 2) -> Dict[str, Any]: """Return {quantity} stop estimates for all active vehicles.""" payload = {"vehicleIdStrings": vehicle_id, "quantity": str(quantity)} response = sess.get( diff --git a/pittapi/sports.py b/pittapi/sports.py index 5b561af..e70f8a7 100644 --- a/pittapi/sports.py +++ b/pittapi/sports.py @@ -56,28 +56,26 @@ def get_next_mens_basketball_game() -> dict: opponent = next_game["competitions"][0]["competitors"][1] homeaway = next_game["competitions"][0]["competitors"][1]["homeAway"] return { - "timestamp" : next_game["date"], - "opponent" : { - "id" : opponent["team"]["id"], - "school" : opponent["team"]["nickname"], - "name" : opponent["team"]["displayName"] + "timestamp": next_game["date"], + "opponent": { + "id": opponent["team"]["id"], + "school": opponent["team"]["nickname"], + "name": opponent["team"]["displayName"], }, - "home_away" : homeaway, - "location" : { - "full_name" : next_game["competitions"][0]["venue"]["fullName"], - "address" : next_game["competitions"][0]["venue"]["address"] + "home_away": homeaway, + "location": { + "full_name": next_game["competitions"][0]["venue"]["fullName"], + "address": next_game["competitions"][0]["venue"]["address"], }, - "status" : status + "status": status, } except IndexError: # IndexError occurs when a next game on the schedule is not present - return { - "status" : "NO_GAME_SCHEDULED" - } + return {"status": "NO_GAME_SCHEDULED"} def get_mens_basketball_standings() -> str: - """returns a string describing the placement of the men's basketball team. eg: '14th in ACC' """ + """returns a string describing the placement of the men's basketball team. eg: '14th in ACC'""" basketball_data = _get_mens_basketball_data() return_value = basketball_data["team"]["standingSummary"] @@ -116,35 +114,35 @@ def get_next_football_game() -> dict: opponent = next_game["competitions"][0]["competitors"][0] homeaway = next_game["competitions"][0]["competitors"][1]["homeAway"] return { - "timestamp" : next_game["date"], - "opponent" : { - "id" : opponent["team"]["id"], - "school" : opponent["team"]["nickname"], - "name" : opponent["team"]["displayName"] + "timestamp": next_game["date"], + "opponent": { + "id": opponent["team"]["id"], + "school": opponent["team"]["nickname"], + "name": opponent["team"]["displayName"], }, - "home_away" : homeaway, - "location" : { - "full_name" : next_game["competitions"][0]["venue"]["fullName"], - "address" : next_game["competitions"][0]["venue"]["address"] + "home_away": homeaway, + "location": { + "full_name": next_game["competitions"][0]["venue"]["fullName"], + "address": next_game["competitions"][0]["venue"]["address"], }, - "status" : status + "status": status, } except IndexError: # IndexError occurs when a next game on the schedule is not present - return { - "status" : "NO_GAME_SCHEDULED" - } + return {"status": "NO_GAME_SCHEDULED"} def get_football_standings() -> str: - """returns a string describing the placement of the football team. eg: '14th in ACC' """ + """returns a string describing the placement of the football team. eg: '14th in ACC'""" football_data = _get_football_data() return_value = football_data["team"]["standingSummary"] return return_value + def _get_mens_basketball_data() -> dict: return requests.get(MENS_BASKETBALL_URL).json() + def _get_football_data() -> dict: return requests.get(FOOTBALL_URL).json() diff --git a/pittapi/textbook.py b/pittapi/textbook.py index 80cbb3e..5c4cd66 100644 --- a/pittapi/textbook.py +++ b/pittapi/textbook.py @@ -242,9 +242,9 @@ def _validate_term(term: str) -> str: def _validate_course(course: str) -> str: """Validates course is a four digit number, - otherwise adds zero(s) to create four digit number or, - raises an exception. - """ + otherwise adds zero(s) to create four digit number or, + raises an exception. + """ if len(course) > 4 or not course.isdigit(): raise ValueError("Invalid course number") elif len(course) == 4: @@ -280,8 +280,8 @@ def find(data, value): def _extract_id(response, course: str, instructor: str, section: str) -> str: """Gathers sections from departments and finds course id by - instructor name or section number. - """ + instructor name or section number. + """ sections = _find_sections(response.json(), course) error = 0 try: @@ -294,26 +294,15 @@ def _extract_id(response, course: str, instructor: str, section: str) -> str: return _find_course_id_by_instructor(sections, instructor.upper()) except LookupError: error += 2 - raise LookupError( - "Unable to find course by " + LOOKUP_ERRORS[error].format(section, instructor) - ) + raise LookupError("Unable to find course by " + LOOKUP_ERRORS[error].format(section, instructor)) def _extract_books(ids: List[str]) -> List[Dict[str, str]]: """Fetches a course's textbook information and returns a list of textbooks for the given course. """ - responses = grequests.imap( - [ - grequests.get(BASE_URL + _construct_query("books", section_id)) - for section_id in ids - ] - ) - books = [ - _filter_dictionary(book, KEYS) - for response in responses - for book in response.json() - ] + responses = grequests.imap([grequests.get(BASE_URL + _construct_query("books", section_id)) for section_id in ids]) + books = [_filter_dictionary(book, KEYS) for response in responses for book in response.json()] return books @@ -347,9 +336,7 @@ def _get_department_number(department_code: str) -> int: if department_number > 22462: department_number += 2 # between codes DSANE and EAS 2 id numbers are skipped. if department_number > 22580: - department_number += ( - 1 # between codes PUBSRV and REHSCI 1 id number is skipped. - ) + department_number += 1 # between codes PUBSRV and REHSCI 1 id number is skipped. return department_number @@ -359,10 +346,7 @@ def get_textbooks(term: str, courses: List[Dict[str, str]]) -> List[Dict[str, st responses = grequests.map( [ grequests.get( - BASE_URL - + _construct_query( - "courses", _get_department_number(department), _validate_term(term) - ), + BASE_URL + _construct_query("courses", _get_department_number(department), _validate_term(term)), timeout=10, ) for department in departments @@ -383,20 +367,11 @@ def get_textbooks(term: str, courses: List[Dict[str, str]]) -> List[Dict[str, st return _extract_books(section_ids) -def get_textbook( - term: str, department: str, course: str, instructor: str = None, section: str = None -) -> List[Dict[str, str]]: +def get_textbook(term: str, department: str, course: str, instructor: str = None, section: str = None) -> List[Dict[str, str]]: """Retrieves textbooks for a given course.""" has_section_or_instructor = (instructor is not None) or (section is not None) if not has_section_or_instructor: raise TypeError("get_textbook() is missing a instructor or section argument") - response = requests.get( - BASE_URL - + _construct_query( - "courses", _get_department_number(department), _validate_term(term) - ) - ) - section_id = _extract_id( - response, department + _validate_course(course), instructor, section - ) + response = requests.get(BASE_URL + _construct_query("courses", _get_department_number(department), _validate_term(term))) + section_id = _extract_id(response, department + _validate_course(course), instructor, section) return _extract_books([section_id]) diff --git a/requirements.txt b/requirements.txt index fcbb4de..6cb2e1f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,70 +1,75 @@ alabaster==0.7.16 appdirs==1.4.4 -attrs==23.2.0 -Babel==2.14.0 +babel==2.15.0 beautifulsoup4==4.12.3 -black==19.10b0 +black==24.4.2 bs4==0.0.2 certifi==2024.2.2 +cfgv==3.4.0 charset-normalizer==3.3.2 click==8.1.7 cov-core==1.15.0 -coverage==7.4.3 +coverage[toml]==7.4.3 cssselect==1.2.0 distlib==0.3.8 -docutils==0.20.1 -execnet==2.0.2 -fake-useragent==1.5.0 -filelock==3.13.1 +docutils==0.21.2 +execnet==2.1.1 +fake-useragent==1.5.1 +filelock==3.14.0 +flake8==7.0.0 gevent==24.2.1 greenlet==3.0.3 grequests==0.7.0 -idna==3.6 +identify==2.5.36 +idna==3.7 imagesize==1.4.1 -importlib_metadata==7.0.2 +importlib-metadata==7.1.0 iniconfig==2.0.0 -Jinja2==3.1.3 -lxml==5.1.0 -MarkupSafe==2.1.5 +jinja2==3.1.4 +lxml==5.2.2 +markupsafe==2.1.5 +mccabe==0.7.0 +mypy-extensions==1.0.0 +nodeenv==1.8.0 nose==1.3.7 nose-cov==1.6 nose-timer==1.0.1 packaging==24.0 parse==1.20.1 pathspec==0.12.1 -platformdirs==4.2.0 -pluggy==1.4.0 +platformdirs==4.2.2 +pluggy==1.5.0 +pre-commit==3.7.1 +pycodestyle==2.11.1 pyee==11.1.0 -Pygments==2.17.2 +pyflakes==3.2.0 +pygments==2.18.0 pyppeteer==2.0.0 pyquery==2.0.0 -pytest==8.1.1 +pytest==8.2.1 pytest-cov==4.1.0 -pytest-xdist==3.5.0 -PyYAML==6.0.1 -regex==2023.12.25 -requests==2.31.0 +pytest-xdist==3.6.1 +pyyaml==6.0.1 +requests==2.32.2 requests-html==0.10.0 responses==0.25.0 -setuptools==69.1.1 +setuptools==70.0.0 snowballstemmer==2.2.0 soupsieve==2.5 -Sphinx==7.2.6 +sphinx==7.3.7 sphinxcontrib-applehelp==1.0.8 sphinxcontrib-devhelp==1.0.6 sphinxcontrib-htmlhelp==2.0.5 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.7 sphinxcontrib-serializinghtml==1.1.10 -toml==0.10.2 -tqdm==4.66.2 -typed_ast==1.5.5 +tqdm==4.66.4 typing==3.7.4.3 -typing_extensions==4.10.0 +typing-extensions==4.11.0 urllib3==1.26.18 -virtualenv==20.25.1 +virtualenv==20.26.2 w3lib==2.1.2 websockets==10.4 -zipp==3.17.0 +zipp==3.18.2 zope.event==5.0 -zope.interface==6.2 +zope.interface==6.4.post1 diff --git a/setup.py b/setup.py index 8d83009..6ee30e2 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,7 @@ # Always prefer setuptools over distutils from setuptools import setup, find_packages + # To use a consistent encoding from codecs import open from os import path @@ -13,97 +14,76 @@ here = path.abspath(path.dirname(__file__)) # Get the long description from the README file -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: +with open(path.join(here, "README.rst"), encoding="utf-8") as f: long_description = f.read() setup( - name='pittapi', - + name="pittapi", # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/single_source_version.html - version='1.0.0', - - description='An API to get data from Pitt and Pitt-related applications.', + version="1.0.0", + description="An API to get data from Pitt and Pitt-related applications.", long_description=long_description, - # The project's main homepage. - url='https://github.com/Pitt-CSC/PittAPI', - + url="https://github.com/Pitt-CSC/PittAPI", # Author details - author='University of Pittsburgh Computer Science Club', - author_email='pittcsc@gmail.com', - + author="University of Pittsburgh Computer Science Club", + author_email="pittcsc@gmail.com", # Choose your license - license='GPLv2', - + license="GPLv2", # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ # How mature is this project? Common values are # 3 - Alpha # 4 - Beta # 5 - Production/Stable - 'Development Status :: 4 - Beta', - + "Development Status :: 4 - Beta", # Indicate who your project is intended for - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Build Tools', - + "Intended Audience :: Developers", + "Topic :: Software Development :: Build Tools", # Pick your license as you wish (should match "license" above) - 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', - + "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", # Specify the Python versions you support here. In particular, ensure # that you indicate whether you support Python 2, Python 3 or both. - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", ], - # What does your project relate to? - keywords='api open-data university-of-pittsburgh pittsburgh pitt', - + keywords="api open-data university-of-pittsburgh pittsburgh pitt", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). - packages=find_packages(exclude=['docs', 'tests']), - + packages=find_packages(exclude=["docs", "tests"]), # Alternatively, if you want to distribute just a my_module.py, uncomment # this: # py_modules=["my_module"], - # List run-time dependencies here. These will be installed by pip when # your project is installed. For an analysis of "install_requires" vs pip's # requirements files see: # https://packaging.python.org/en/latest/requirements.html install_requires=[ - 'BeautifulSoup4', - 'Requests', - 'requests_html', - 'grequests', - 'lxml', - 'parse', + "BeautifulSoup4", + "Requests", + "requests_html", + "grequests", + "lxml", + "parse", ], - # List additional groups of dependencies here (e.g. development # dependencies). You can install these using the following syntax, # for example: # $ pip install -e .[dev,test] extras_require={ - 'test': [ - 'timeout-decorator', - 'nose', - 'nose-cov', - 'nose-timer' - ], + "test": ["timeout-decorator", "nose", "nose-cov", "nose-timer"], }, - # If there are data files included in your packages that need to be # installed, specify them here. If using Python 2.6 or less, then these # have to be included in MANIFEST.in as well. # package_data={ # 'sample': ['package_data.dat'], # }, - # Although 'package_data' is the preferred approach, in some case you may # need to place data files outside of your packages. See: # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa diff --git a/tests/__init__.py b/tests/__init__.py index 7bd539f..05531a0 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -19,4 +19,4 @@ import warnings -warnings.simplefilter('ignore') +warnings.simplefilter("ignore") diff --git a/tests/course_test.py b/tests/course_test.py index daa79d3..1666c67 100644 --- a/tests/course_test.py +++ b/tests/course_test.py @@ -22,7 +22,15 @@ from pittapi import course from pittapi.course import Attribute, Component, Course, CourseDetails, Instructor, Meeting, Section, SectionDetails, Subject -from tests.mocks.course_mocks import mocked_subject_data, mocked_courses_data, mocked_courses_data_invalid, mocked_course_info_data, mocked_course_sections_data, mocked_section_details_data +from tests.mocks.course_mocks import ( + mocked_subject_data, + mocked_courses_data, + mocked_courses_data_invalid, + mocked_course_info_data, + mocked_course_sections_data, + mocked_section_details_data, +) + class CourseTest(unittest.TestCase): def setUp(self): @@ -33,47 +41,47 @@ def test_validate_term(self): # If convert to string self.assertTrue(isinstance(course._validate_term(2191), str)) - self.assertEqual(course._validate_term(2191), '2191') - self.assertEqual(course._validate_term('2191'), '2191') + self.assertEqual(course._validate_term(2191), "2191") + self.assertEqual(course._validate_term("2191"), "2191") - self.assertRaises(ValueError, course._validate_term, '214') - self.assertRaises(ValueError, course._validate_term, '1111') - self.assertRaises(ValueError, course._validate_term, '12345') + self.assertRaises(ValueError, course._validate_term, "214") + self.assertRaises(ValueError, course._validate_term, "1111") + self.assertRaises(ValueError, course._validate_term, "12345") def test_validate_subject(self): - self.assertEqual(course._validate_subject('CS'), 'CS') + self.assertEqual(course._validate_subject("CS"), "CS") - self.assertRaises(ValueError, course._validate_subject, 'foobar') + self.assertRaises(ValueError, course._validate_subject, "foobar") def test_validate_course(self): - self.assertEqual(course._validate_course(7), '0007') - self.assertEqual(course._validate_course(449), '0449') - self.assertEqual(course._validate_course(1501), '1501') + self.assertEqual(course._validate_course(7), "0007") + self.assertEqual(course._validate_course(449), "0449") + self.assertEqual(course._validate_course(1501), "1501") - self.assertEqual(course._validate_course('7'), '0007') - self.assertEqual(course._validate_course('0007'), '0007') - self.assertEqual(course._validate_course('449'), '0449') - self.assertEqual(course._validate_course('1501'), '1501') + self.assertEqual(course._validate_course("7"), "0007") + self.assertEqual(course._validate_course("0007"), "0007") + self.assertEqual(course._validate_course("449"), "0449") + self.assertEqual(course._validate_course("1501"), "1501") self.assertRaises(ValueError, course._validate_course, -1) self.assertRaises(ValueError, course._validate_course, 0) - self.assertRaises(ValueError, course._validate_course, '') - self.assertRaises(ValueError, course._validate_course, 'A00') - self.assertRaises(ValueError, course._validate_course, 'Hello') - self.assertRaises(ValueError, course._validate_course, '10000') + self.assertRaises(ValueError, course._validate_course, "") + self.assertRaises(ValueError, course._validate_course, "A00") + self.assertRaises(ValueError, course._validate_course, "Hello") + self.assertRaises(ValueError, course._validate_course, "10000") def test_get_subject_courses(self): course._get_subject_courses = MagicMock(return_value=mocked_courses_data) - subject_courses = course.get_subject_courses('CS') + subject_courses = course.get_subject_courses("CS") - course._get_subject_courses.assert_called_once_with('CS') + course._get_subject_courses.assert_called_once_with("CS") self.assertTrue(isinstance(subject_courses, Subject)) self.assertEqual(len(subject_courses.courses), 1) - self.assertTrue('0007' in subject_courses.courses) - test_course = subject_courses.courses['0007'] + self.assertTrue("0007" in subject_courses.courses) + test_course = subject_courses.courses["0007"] self.assertTrue(isinstance(test_course, Course)) def test_get_subject_courses_invalid(self): @@ -83,37 +91,37 @@ def test_get_subject_courses_invalid(self): course._get_subject_courses.assert_not_called() def test_get_course_details(self): - course._get_course_id = MagicMock(return_value='105611') + course._get_course_id = MagicMock(return_value="105611") course._get_course_info = MagicMock(return_value=mocked_course_info_data) course._get_course_sections = MagicMock(return_value=mocked_course_sections_data) - course_sections = course.get_course_details('2231', 'CS', '0007') + course_sections = course.get_course_details("2231", "CS", "0007") self.assertTrue(isinstance(course_sections, CourseDetails)) self.assertTrue(isinstance(course_sections.course, Course)) course_obj = course_sections.course - self.assertEqual(course_obj.subject_code, 'CS') - self.assertEqual(course_obj.course_number, '0007') - self.assertEqual(course_obj.course_id, '105611') - self.assertEqual(course_obj.course_title, 'INTRO TO COMPUTER PROGRAMMING') + self.assertEqual(course_obj.subject_code, "CS") + self.assertEqual(course_obj.course_number, "0007") + self.assertEqual(course_obj.course_id, "105611") + self.assertEqual(course_obj.course_title, "INTRO TO COMPUTER PROGRAMMING") self.assertEqual(len(course_sections.sections), 1) test_attribute = course_sections.attributes[0] self.assertTrue(isinstance(test_attribute, Attribute)) - self.assertEqual(test_attribute.attribute, 'DSGE') - self.assertEqual(test_attribute.attribute_description, '*DSAS General Ed. Requirements') - self.assertEqual(test_attribute.value, 'ALG') + self.assertEqual(test_attribute.attribute, "DSGE") + self.assertEqual(test_attribute.attribute_description, "*DSAS General Ed. Requirements") + self.assertEqual(test_attribute.value, "ALG") - self.assertEqual(test_attribute.value_description, 'Algebra') + self.assertEqual(test_attribute.value_description, "Algebra") test_section = course_sections.sections[0] self.assertTrue(isinstance(test_section, Section)) - self.assertEqual(test_section.term, '2231') - self.assertEqual(test_section.session, 'Academic Term') - self.assertEqual(test_section.section_number, '1000') - self.assertEqual(test_section.class_number, '27815') - self.assertEqual(test_section.section_type, 'REC') - self.assertEqual(test_section.status, 'Open') + self.assertEqual(test_section.term, "2231") + self.assertEqual(test_section.session, "Academic Term") + self.assertEqual(test_section.section_number, "1000") + self.assertEqual(test_section.class_number, "27815") + self.assertEqual(test_section.section_type, "REC") + self.assertEqual(test_section.status, "Open") self.assertEqual(len(test_section.instructors), 1) self.assertEqual(len(test_section.meetings), 1) @@ -136,36 +144,36 @@ def test_get_course_details(self): def test_get_section_details(self): course._get_section_details = MagicMock(return_value=mocked_section_details_data) - section_details = course.get_section_details('2231', '27815') + section_details = course.get_section_details("2231", "27815") self.assertTrue(isinstance(section_details, Section)) - self.assertEqual(section_details.term, '2231') - self.assertEqual(section_details.session, 'Academic Term') - self.assertEqual(section_details.class_number, '27815') - self.assertEqual(section_details.section_type, 'REC') - self.assertEqual(section_details.status, 'Open') + self.assertEqual(section_details.term, "2231") + self.assertEqual(section_details.session, "Academic Term") + self.assertEqual(section_details.class_number, "27815") + self.assertEqual(section_details.section_type, "REC") + self.assertEqual(section_details.status, "Open") self.assertIsNone(section_details.instructors) test_meeting = section_details.meetings[0] self.assertTrue(isinstance(test_meeting, Meeting)) - self.assertEqual(test_meeting.days, 'Fr') - self.assertEqual(test_meeting.start_time, '10:00AM') - self.assertEqual(test_meeting.end_time, '10:50AM') - self.assertEqual(test_meeting.start_date, '08/29/2022') - self.assertEqual(test_meeting.end_date, '12/09/2022') + self.assertEqual(test_meeting.days, "Fr") + self.assertEqual(test_meeting.start_time, "10:00AM") + self.assertEqual(test_meeting.end_time, "10:50AM") + self.assertEqual(test_meeting.start_date, "08/29/2022") + self.assertEqual(test_meeting.end_date, "12/09/2022") test_instructor = test_meeting.instructors[0] self.assertTrue(isinstance(test_instructor, Instructor)) - self.assertEqual(test_instructor.name, 'Robert Fishel') - self.assertEqual(test_instructor.email, 'rmf105@pitt.edu') + self.assertEqual(test_instructor.name, "Robert Fishel") + self.assertEqual(test_instructor.email, "rmf105@pitt.edu") test_details = section_details.details self.assertTrue(isinstance(test_details, SectionDetails)) - self.assertEqual(test_details.units, '0 units') - self.assertEqual(test_details.class_capacity, '28') - self.assertEqual(test_details.enrollment_total, '24') - self.assertEqual(test_details.enrollment_available, '4') - self.assertEqual(test_details.wait_list_capacity, '50') - self.assertEqual(test_details.wait_list_total, '7') - self.assertEqual(test_details.valid_to_enroll, 'T') + self.assertEqual(test_details.units, "0 units") + self.assertEqual(test_details.class_capacity, "28") + self.assertEqual(test_details.enrollment_total, "24") + self.assertEqual(test_details.enrollment_available, "4") + self.assertEqual(test_details.wait_list_capacity, "50") + self.assertEqual(test_details.wait_list_total, "7") + self.assertEqual(test_details.valid_to_enroll, "T") self.assertIsNone(test_details.combined_section_numbers) diff --git a/tests/dining_test.py b/tests/dining_test.py index 49d1b14..7259acb 100644 --- a/tests/dining_test.py +++ b/tests/dining_test.py @@ -26,47 +26,61 @@ from pittapi import dining -SAMPLE_PATH = Path() / 'tests' / 'samples' +SAMPLE_PATH = Path() / "tests" / "samples" class DiningTest(unittest.TestCase): def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) - with (SAMPLE_PATH / 'dining_schedule.json').open() as f: + with (SAMPLE_PATH / "dining_schedule.json").open() as f: self.dining_schedule_data = json.load(f) - with (SAMPLE_PATH / 'dining_locations.json').open() as f: + with (SAMPLE_PATH / "dining_locations.json").open() as f: self.dining_locations_data = json.load(f) - with (SAMPLE_PATH / 'dining_menu.json').open() as f: + with (SAMPLE_PATH / "dining_menu.json").open() as f: self.dining_menu_data = json.load(f) - @responses.activate def test_get_locations(self): - responses.add(responses.GET, - "https://api.dineoncampus.com/v1/locations/status?site_id=5e6fcc641ca48e0cacd93b04&platform=", - json=self.dining_locations_data, status=200) + responses.add( + responses.GET, + "https://api.dineoncampus.com/v1/locations/status?site_id=5e6fcc641ca48e0cacd93b04&platform=", + json=self.dining_locations_data, + status=200, + ) self.assertIsInstance(dining.get_locations(), dict) @responses.activate def test_get_location_hours(self): - responses.add(responses.GET, - "https://api.dineoncampus.com/v1/locations/weekly_schedule?site_id=5e6fcc641ca48e0cacd93b04&date=%222024-04-12%22", - json=self.dining_schedule_data, status=200) + responses.add( + responses.GET, + "https://api.dineoncampus.com/v1/locations/weekly_schedule?site_id=5e6fcc641ca48e0cacd93b04&date=%222024-04-12%22", + json=self.dining_schedule_data, + status=200, + ) self.assertIsInstance(dining.get_location_hours("The Eatery", datetime.datetime(2024, 4, 12)), dict) @responses.activate def test_get_location_menu(self): - responses.add(responses.GET, - "https://api.dineoncampus.com/v1/locations/status?site_id=5e6fcc641ca48e0cacd93b04&platform=", - json=self.dining_locations_data, status=200) - responses.add(responses.GET, - "https://api.dineoncampus.com/v1/location/610b1f78e82971147c9f8ba5/periods?platform=0&date=24-04-12", - json=self.dining_menu_data, status=200) - responses.add(responses.GET, - "https://api.dineoncampus.com/v1/location/610b1f78e82971147c9f8ba5/periods/659daa4d351d53068df67835?platform=0&date=24-04-12", - json=self.dining_menu_data, status=200) + responses.add( + responses.GET, + "https://api.dineoncampus.com/v1/locations/status?site_id=5e6fcc641ca48e0cacd93b04&platform=", + json=self.dining_locations_data, + status=200, + ) + responses.add( + responses.GET, + "https://api.dineoncampus.com/v1/location/610b1f78e82971147c9f8ba5/periods?platform=0&date=24-04-12", + json=self.dining_menu_data, + status=200, + ) + responses.add( + responses.GET, + "https://api.dineoncampus.com/v1/location/610b1f78e82971147c9f8ba5/periods/659daa4d351d53068df67835?platform=0&date=24-04-12", + json=self.dining_menu_data, + status=200, + ) locations = dining.get_location_menu("The Eatery", datetime.datetime(2024, 4, 12), "Breakfast") self.assertIsInstance(locations, dict) diff --git a/tests/laundry_test.py b/tests/laundry_test.py index 15025d3..28fe61d 100644 --- a/tests/laundry_test.py +++ b/tests/laundry_test.py @@ -25,39 +25,41 @@ from pittapi import laundry -SAMPLE_PATH = Path() / 'tests' / 'samples' +SAMPLE_PATH = Path() / "tests" / "samples" TEST_BUILDING = "SUTH_EAST" class LaundryTest(unittest.TestCase): def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) - with open(SAMPLE_PATH / 'laundry_mock_response.json', 'r') as file: + with open(SAMPLE_PATH / "laundry_mock_response.json", "r") as file: self.mock_data = json.load(file) @responses.activate def test_get_status_simple(self): responses.add( responses.GET, - 'https://www.laundryview.com/api/currentRoomData?school_desc_key=197&location=' + laundry.LOCATION_LOOKUP[TEST_BUILDING], + "https://www.laundryview.com/api/currentRoomData?school_desc_key=197&location=" + + laundry.LOCATION_LOOKUP[TEST_BUILDING], json=self.mock_data, - status=200 + status=200, ) status = laundry.get_status_simple(TEST_BUILDING) self.assertIsInstance(status, dict) - self.assertEqual(status['building'], TEST_BUILDING) - self.assertEqual(status['free_washers'], 7) - self.assertEqual(status['free_dryers'], 2) - self.assertEqual(status['total_washers'], 10) - self.assertEqual(status['total_dryers'], 10) + self.assertEqual(status["building"], TEST_BUILDING) + self.assertEqual(status["free_washers"], 7) + self.assertEqual(status["free_dryers"], 2) + self.assertEqual(status["total_washers"], 10) + self.assertEqual(status["total_dryers"], 10) @responses.activate def test_get_status_detailed(self): responses.add( responses.GET, - 'https://www.laundryview.com/api/currentRoomData?school_desc_key=197&location=' + laundry.LOCATION_LOOKUP[TEST_BUILDING], + "https://www.laundryview.com/api/currentRoomData?school_desc_key=197&location=" + + laundry.LOCATION_LOOKUP[TEST_BUILDING], json=self.mock_data, - status=200 + status=200, ) status = laundry.get_status_detailed(TEST_BUILDING) self.assertIsInstance(status, list) diff --git a/tests/library_test.py b/tests/library_test.py index bde179c..acce522 100644 --- a/tests/library_test.py +++ b/tests/library_test.py @@ -25,23 +25,18 @@ from pittapi import library -SAMPLE_PATH = Path() / 'tests' / 'samples' +SAMPLE_PATH = Path() / "tests" / "samples" class LibraryTest(unittest.TestCase): def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) - with (SAMPLE_PATH / 'library_mock_response_water.json').open() as f: + with (SAMPLE_PATH / "library_mock_response_water.json").open() as f: self.library_query = json.load(f) @responses.activate def test_get_documents(self): - responses.add( - responses.GET, - library.LIBRARY_URL + library.QUERY_START + "water", - json=self.library_query, - status=200 - ) + responses.add(responses.GET, library.LIBRARY_URL + library.QUERY_START + "water", json=self.library_query, status=200) query_result = library.get_documents("water") self.assertIsInstance(query_result, dict) self.assertEqual(query_result["pages"], 10) diff --git a/tests/mocks/course_mocks.py b/tests/mocks/course_mocks.py index aafc59a..9f2918d 100644 --- a/tests/mocks/course_mocks.py +++ b/tests/mocks/course_mocks.py @@ -1,20 +1,7 @@ -mocked_subject_data = { - "subjects" : [ - { - "subject" : "CS", - "descr" : "Computer Science" - } - ] -} +mocked_subject_data = {"subjects": [{"subject": "CS", "descr": "Computer Science"}]} mocked_courses_data = { - "courses" : [ - { - "catalog_nbr": "0007", - "descr": "INTRODUCTION TO COMPUTER PROGRAMMING", - "crse_id": "105611" - } - ] + "courses": [{"catalog_nbr": "0007", "descr": "INTRODUCTION TO COMPUTER PROGRAMMING", "crse_id": "105611"}] } mocked_courses_data_invalid = {} @@ -30,29 +17,20 @@ "course_title": "INTRODUCTION TO COMPUTER PROGRAMMING", "rqmnt_designtn": "", "effdt": "2018-06-30", - "components": [ - { - "descr": "Lecture", - "optional": "N" - }, - { - "descr": "Recitation", - "optional": "N" - } - ], + "components": [{"descr": "Lecture", "optional": "N"}, {"descr": "Recitation", "optional": "N"}], "attributes": [ { "crse_attribute": "DSGE", "crse_attribute_descr": "*DSAS General Ed. Requirements", "crse_attribute_value": "ALG", - "crse_attribute_value_descr": "Algebra" + "crse_attribute_value_descr": "Algebra", }, { "crse_attribute": "DSGE", "crse_attribute_descr": "*DSAS General Ed. Requirements", "crse_attribute_value": "QFR", - "crse_attribute_value_descr": "Quant.-Formal Reasoning" - } + "crse_attribute_value_descr": "Quant.-Formal Reasoning", + }, ], "offerings": [ { @@ -67,35 +45,13 @@ "req_group": "", "planner_message": "You have no active career, so you can not add this course to a planner.", "open_terms": [ - { - "strm": "2224", - "descr": "Spring Term 2021-2022", - "default_term": False - }, - { - "strm": "2227", - "descr": "Summer Term 2021-2022", - "default_term": False - }, - { - "strm": "2231", - "descr": "Fall Term 2022-2023", - "default_term": True - } + {"strm": "2224", "descr": "Spring Term 2021-2022", "default_term": False}, + {"strm": "2227", "descr": "Summer Term 2021-2022", "default_term": False}, + {"strm": "2231", "descr": "Fall Term 2022-2023", "default_term": True}, ], - "enrollable_terms": [ - { - "strm": "2224" - }, - { - "strm": "2227" - }, - { - "strm": "2231" - } - ] + "enrollable_terms": [{"strm": "2224"}, {"strm": "2227"}, {"strm": "2231"}], } - ] + ], } } @@ -131,12 +87,7 @@ "end_dt": "12/09/2022", "units": "0", "topic": "", - "instructors": [ - { - "name": "Robert Fishel", - "email": "rmf105@pitt.edu" - } - ], + "instructors": [{"name": "Robert Fishel", "email": "rmf105@pitt.edu"}], "section_type": "REC", "meetings": [ { @@ -145,12 +96,12 @@ "end_time": "10.50.00.000000-05:00", "start_dt": "08/29/2022", "end_dt": "12/09/2022", - "instructor": "Robert Fishel" + "instructor": "Robert Fishel", } ], - "reserve_caps": [] + "reserve_caps": [], } - ] + ], } mocked_section_details_data = { @@ -181,7 +132,7 @@ "campus_code": "PIT", "location": "Pittsburgh Campus", "topic": "", - "class_components": "
Lecture Required, Recitation Required
" + "class_components": '
Lecture Required, Recitation Required
', }, "meetings": [ { @@ -191,17 +142,12 @@ "meeting_time_end": "10:50AM", "bldg_cd": "SENSQ", "meeting_topic": "TBA", - "instructors": [ - { - "name": "Robert Fishel", - "email": "rmf105@pitt.edu" - } - ], + "instructors": [{"name": "Robert Fishel", "email": "rmf105@pitt.edu"}], "start_date": "08/29/2022", "end_date": "12/09/2022", "topic": "TBA", "show_topic": False, - "date_range": "08/29/2022 - 12/09/2022" + "date_range": "08/29/2022 - 12/09/2022", } ], "enrollment_information": { @@ -209,21 +155,18 @@ "drop_consent": "", "enroll_requirements": "", "requirement_desig": "", - "class_attributes": "DSAS Algebra General Ed. Requirement \rDSAS Quant.-Formal Reason General Ed. Requirement \rAsian Studies" + "class_attributes": "DSAS Algebra General Ed. Requirement \rDSAS Quant.-Formal Reason General Ed. Requirement \rAsian Studies", }, "class_availability": { "class_capacity": "28", "enrollment_total": "24", "enrollment_available": 4, "wait_list_capacity": "50", - "wait_list_total": "7" + "wait_list_total": "7", }, "reserve_caps": [], "is_combined": False, - "notes": { - "class_notes": "", - "subject_notes": "" - }, + "notes": {"class_notes": "", "subject_notes": ""}, "catalog_descr": { "crse_catalog_description": "This is a first course in computer science programming. It is recommended for those students intending to major in computer science who do not have the required background for cs 0401. It may also be of interest to students majoring in one of the social sciences or humanities. The focus of the course is on problem analysis and the development of algorithms and computer programs in a modern high-level language." }, @@ -231,14 +174,11 @@ "txb_none": "N", "txb_status": "P", "txb_special_instructions": "", - "textbooks_message": "Textbooks to be determined" + "textbooks_message": "Textbooks to be determined", }, - "valid_to_enroll": "T" - }, - "class_enroll_info": { - "last_enrl_dt_passed": False, - "is_related": True + "valid_to_enroll": "T", }, + "class_enroll_info": {"last_enrl_dt_passed": False, "is_related": True}, "additionalLinks": [], "cfg": { "is_related": False, @@ -272,12 +212,12 @@ "show_topic": False, "show_add_to_wish_list": False, "wish_list_enabled": False, - "show_actions": True + "show_actions": True, }, "messages": { "shareLink": "Copy link to share the class with friends.", "shareSocial": "Or share on social media networks.", "reserveInfo": "Seats in this class have been reserved for students for the specified programs, majors or groups listed below. Reserved seats are subject to change without notice.", - "noMeetingInfo": "No meeting info found" - } + "noMeetingInfo": "No meeting info found", + }, } diff --git a/tests/news_test.py b/tests/news_test.py index aec2f66..e4aef05 100644 --- a/tests/news_test.py +++ b/tests/news_test.py @@ -21,6 +21,7 @@ from pittapi import news + @unittest.skip class NewsTest(unittest.TestCase): def test_get_news_default(self): diff --git a/tests/people_test.py b/tests/people_test.py index 616599f..eacecaf 100644 --- a/tests/people_test.py +++ b/tests/people_test.py @@ -21,8 +21,7 @@ import responses from pittapi import people -RAMIREZ_TEST_DATA = ( - ''' +RAMIREZ_TEST_DATA = """
@@ -66,10 +65,9 @@
- ''') + """ -TOO_MANY_TEST_DATA = ( - ''' +TOO_MANY_TEST_DATA = """
Too many people matched your criteria. Please try searching by username, phone, email, or by enclosing your @@ -81,10 +79,9 @@
- ''') + """ -NONE_FOUND_TEST_DATA = ( - ''' +NONE_FOUND_TEST_DATA = """
- ''') + """ class PeopleTest(unittest.TestCase): @responses.activate def test_people_get_person(self): - responses.add(responses.POST, people.PEOPLE_SEARCH_URL, - body=RAMIREZ_TEST_DATA, status=200) + responses.add(responses.POST, people.PEOPLE_SEARCH_URL, body=RAMIREZ_TEST_DATA, status=200) ans = people.get_person("John C Ramirez") self.assertIsInstance(ans, list) - self.assertTrue(ans[0]['name'] == "Ramirez, John C") - self.assertTrue(ans[0]['office_phone'] == "(412) 624-8441") + self.assertTrue(ans[0]["name"] == "Ramirez, John C") + self.assertTrue(ans[0]["office_phone"] == "(412) 624-8441") @responses.activate def test_people_get_person_too_many(self): - responses.add(responses.POST, people.PEOPLE_SEARCH_URL, - body=TOO_MANY_TEST_DATA, status=200) + responses.add(responses.POST, people.PEOPLE_SEARCH_URL, body=TOO_MANY_TEST_DATA, status=200) ans = people.get_person("Smith") - self.assertIsInstance(ans,list) - self.assertEqual(ans, [{"ERROR":"Too many people matched your criteria."}]) + self.assertIsInstance(ans, list) + self.assertEqual(ans, [{"ERROR": "Too many people matched your criteria."}]) @responses.activate def test_people_get_person_none(self): - responses.add(responses.POST, people.PEOPLE_SEARCH_URL, - body=NONE_FOUND_TEST_DATA, status=200) + responses.add(responses.POST, people.PEOPLE_SEARCH_URL, body=NONE_FOUND_TEST_DATA, status=200) ans = people.get_person("Lebron Iverson James Jordan Kobe") - self.assertIsInstance(ans,list) - self.assertEqual(ans, [{"ERROR":"No one found."}]) + self.assertIsInstance(ans, list) + self.assertEqual(ans, [{"ERROR": "No one found."}]) diff --git a/tests/shuttle_test.py b/tests/shuttle_test.py index 6dba8bf..e8a0855 100644 --- a/tests/shuttle_test.py +++ b/tests/shuttle_test.py @@ -28,9 +28,9 @@ class ShuttleTest(unittest.TestCase): def test_get_map_vehicle_points(self): responses.add( method=responses.GET, - url='http://www.pittshuttle.com/Services/JSONPRelay.svc/GetMapVehiclePoints?ApiKey=8882812681', + url="http://www.pittshuttle.com/Services/JSONPRelay.svc/GetMapVehiclePoints?ApiKey=8882812681", json=[{}, {}, {}], - status=200 + status=200, ) self.assertIsInstance(shuttle.get_map_vehicle_points(), list) @@ -38,9 +38,9 @@ def test_get_map_vehicle_points(self): def test_get_route_stop_arrivals(self): responses.add( method=responses.GET, - url='http://www.pittshuttle.com/Services/JSONPRelay.svc/GetRouteStopArrivals?ApiKey=8882812681&TimesPerStopString=1', + url="http://www.pittshuttle.com/Services/JSONPRelay.svc/GetRouteStopArrivals?ApiKey=8882812681&TimesPerStopString=1", json=[{}, {}, {}], - status=200 + status=200, ) self.assertIsInstance(shuttle.get_route_stop_arrivals(), list) @@ -48,20 +48,20 @@ def test_get_route_stop_arrivals(self): def test_vehicle_route_stop_estimates(self): responses.add( method=responses.GET, - url='http://www.pittshuttle.com/Services/JSONPRelay.svc/GetVehicleRouteStopEstimates?vehicleIdStrings=25&quantity=4', + url="http://www.pittshuttle.com/Services/JSONPRelay.svc/GetVehicleRouteStopEstimates?vehicleIdStrings=25&quantity=4", json=[{"Estimates": [{}, {}, {}, {}]}], - status=200 + status=200, ) stop_estimates = shuttle.get_vehicle_route_stop_estimates(25, 4) self.assertIsInstance(stop_estimates, list) - self.assertEqual(len(stop_estimates[0]['Estimates']), 4) + self.assertEqual(len(stop_estimates[0]["Estimates"]), 4) @responses.activate def test_get_routes(self): responses.add( method=responses.GET, - url='http://www.pittshuttle.com/Services/JSONPRelay.svc/GetRoutesForMap?ApiKey=8882812681', + url="http://www.pittshuttle.com/Services/JSONPRelay.svc/GetRoutesForMap?ApiKey=8882812681", json=[{}, {}, {}], - status=200 + status=200, ) self.assertIsInstance(shuttle.get_routes(), list) diff --git a/tests/sports_test.py b/tests/sports_test.py index bb6deb3..7f0dcf3 100644 --- a/tests/sports_test.py +++ b/tests/sports_test.py @@ -19,23 +19,20 @@ from pittapi import sports + class LibraryTest(unittest.TestCase): def setUp(self): mocked_basketball_data = { - "team" : { + "team": { "id": "221", "record": { "items": [ - { - "description": "Overall Record", - "type": "total", - "summary": "11-21" - }, + {"description": "Overall Record", "type": "total", "summary": "11-21"}, { "description": "Home Record", "type": "home", "summary": "9-11", - } + }, ] }, "nextEvent": [ @@ -43,65 +40,51 @@ def setUp(self): "date": "2022-03-08T19:00Z", "competitions": [ { - "venue": { - "fullName": "Barclays Center", - "address": { - "city": "Brooklyn", - "state": "NY" - } - }, + "venue": {"fullName": "Barclays Center", "address": {"city": "Brooklyn", "state": "NY"}}, "competitors": [ { "id": "221", - "homeAway" : "home", - "team" : { + "homeAway": "home", + "team": { "id": "221", "location": "Pittsburgh", "nickname": "Pittsburgh", "abbreviation": "PITT", - "displayName": "Pittsburgh Panthers" - } + "displayName": "Pittsburgh Panthers", + }, }, { "id": "103", "homeAway": "away", - "team" : { + "team": { "id": "103", "location": "Boston College", "nickname": "Boston College", "abbreviation": "BC", - "displayName": "Boston College Eagles" - } - } + "displayName": "Boston College Eagles", + }, + }, ], - "status": { - "type": { - "name": "STATUS_FINAL" - } - } + "status": {"type": {"name": "STATUS_FINAL"}}, } - ] + ], } ], - "standingSummary": "12th in ACC" + "standingSummary": "12th in ACC", } } mocked_football_data = { - "team" : { + "team": { "id": "221", "name": "Pittsburgh", "record": { "items": [ - { - "description": "Overall Record", - "type": "total", - "summary": "10-2" - }, + {"description": "Overall Record", "type": "total", "summary": "10-2"}, { "description": "Home Record", "type": "home", "summary": "5-2", - } + }, ] }, "nextEvent": [ @@ -113,45 +96,38 @@ def setUp(self): { "venue": { "fullName": "Bank of America Stadium", - "address": { - "city": "Charlotte", - "state": "NC" - } + "address": {"city": "Charlotte", "state": "NC"}, }, "competitors": [ { "id": "221", - "homeAway" : "away", - "team" : { + "homeAway": "away", + "team": { "id": "221", "location": "Pittsburgh", "nickname": "Pittsburgh", "abbreviation": "PITT", - "displayName": "Pittsburgh Panthers" - } + "displayName": "Pittsburgh Panthers", + }, }, { "id": "104", "homeAway": "away", - "team" : { + "team": { "id": "103", "location": "Wake Forest", "nickname": "Wake Forest", "abbreviation": "WAKE", - "displayName": "Wake Forest Deamon Deacons" - } - } + "displayName": "Wake Forest Deamon Deacons", + }, + }, ], - "status": { - "type": { - "name": "STATUS_IN_PROGRESS" - } - } + "status": {"type": {"name": "STATUS_IN_PROGRESS"}}, } - ] + ], } ], - "standingSummary": "1st in ACC - Coastal" + "standingSummary": "1st in ACC - Coastal", } } sports._get_mens_basketball_data = MagicMock(return_value=mocked_basketball_data) @@ -161,12 +137,7 @@ def test_get_mens_basketball_record(self): self.assertEqual("11-21", sports.get_mens_basketball_record()) def test_get_mens_basketball_record_offseason(self): - offseason_data = { - "team": { - "id": "221", - "record": {} - } - } + offseason_data = {"team": {"id": "221", "record": {}}} sports._get_mens_basketball_data = MagicMock(return_value=offseason_data) self.assertEqual("There's no record right now.", sports.get_mens_basketball_record()) @@ -175,12 +146,7 @@ def test_get_football_record(self): self.assertEqual("10-2", sports.get_football_record()) def test_get_football_record_offseason(self): - offseason_data = { - "team": { - "id": "221", - "record": {} - } - } + offseason_data = {"team": {"id": "221", "record": {}}} sports._get_football_data = MagicMock(return_value=offseason_data) self.assertEqual("There's no record right now.", sports.get_football_record()) @@ -210,11 +176,7 @@ def test_get_next_football_game(self): self.assertNotEqual("NO_GAME_SCHEDULED", next_game_details["status"]) def test_get_next_mens_basketball_game_offseason(self): - offseason_data = { - "team": { - "nextEvent": [] - } - } + offseason_data = {"team": {"nextEvent": []}} sports._get_mens_basketball_data = MagicMock(return_value=offseason_data) next_game_details = sports.get_next_mens_basketball_game() @@ -223,11 +185,7 @@ def test_get_next_mens_basketball_game_offseason(self): self.assertEqual("NO_GAME_SCHEDULED", next_game_details["status"]) def test_get_next_football_game_offseason(self): - offseason_data = { - "team": { - "nextEvent": [] - } - } + offseason_data = {"team": {"nextEvent": []}} sports._get_football_data = MagicMock(return_value=offseason_data) next_game_details = sports.get_next_football_game() diff --git a/tests/status_test.py b/tests/status_test.py index 69c33d8..6c521a8 100644 --- a/tests/status_test.py +++ b/tests/status_test.py @@ -25,18 +25,16 @@ from pittapi import status -SAMPLE_PATH = Path() / 'tests' / 'samples' +SAMPLE_PATH = Path() / "tests" / "samples" class StatusTest(unittest.TestCase): def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) - with (SAMPLE_PATH / 'status.json').open() as f: + with (SAMPLE_PATH / "status.json").open() as f: self.status_data = json.load(f) @responses.activate def test_get_status(self): - responses.add(responses.GET, - 'https://status.pitt.edu/index.json', - json=self.status_data, status=200) + responses.add(responses.GET, "https://status.pitt.edu/index.json", json=self.status_data, status=200) self.assertIsInstance(status.get_status(), dict) diff --git a/tests/textbook_test.py b/tests/textbook_test.py index e28aca3..c01e5b5 100644 --- a/tests/textbook_test.py +++ b/tests/textbook_test.py @@ -25,8 +25,8 @@ from pittapi import textbook -TERM = '1000' -SAMPLE_PATH = Path() / 'tests' / 'samples' +TERM = "1000" +SAMPLE_PATH = Path() / "tests" / "samples" print(SAMPLE_PATH.absolute()) @@ -36,147 +36,134 @@ def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) self.validate_term = textbook._validate_term self.validate_course = textbook._validate_course - with (SAMPLE_PATH /'textbook_courses_CS.json').open() as f: + with (SAMPLE_PATH / "textbook_courses_CS.json").open() as f: self.cs_data = json.load(f) - with (SAMPLE_PATH / 'textbook_courses_STAT.json').open() as f: + with (SAMPLE_PATH / "textbook_courses_STAT.json").open() as f: self.stat_data = json.load(f) @responses.activate def test_textbook_get_textbook(self): - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=200) - instructor_test = textbook.get_textbook( - term=TERM, - department='CS', - course='445', - instructor='GARRISON III' + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=200 ) + instructor_test = textbook.get_textbook(term=TERM, department="CS", course="445", instructor="GARRISON III") - section_test = textbook.get_textbook( - term=TERM, - department='CS', - course='445', - section='1030' - ) + section_test = textbook.get_textbook(term=TERM, department="CS", course="445", section="1030") self.assertIsInstance(instructor_test, list) self.assertIsInstance(section_test, list) @responses.activate def test_textbook_get_textbooks(self): - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=200) - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22594&term_id=1000', - json=self.stat_data, status=200) + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=200 + ) + responses.add( + responses.GET, + "http://pitt.verbacompare.com/compare/courses/?id=22594&term_id=1000", + json=self.stat_data, + status=200, + ) multi_book_test = textbook.get_textbooks( term=TERM, courses=[ - {'department': 'STAT', 'course': '1000', 'instructor': 'WANG'}, - {'department': 'CS', 'course': '445', 'section': '1030'}]) + {"department": "STAT", "course": "1000", "instructor": "WANG"}, + {"department": "CS", "course": "445", "section": "1030"}, + ], + ) self.assertIsInstance(multi_book_test, list) @responses.activate def test_get_textbook_invalid_term(self): - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=200) - self.assertRaises(TypeError, textbook.get_textbook, '0000', 'CS', '401') + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=200 + ) + self.assertRaises(TypeError, textbook.get_textbook, "0000", "CS", "401") @responses.activate def test_get_textbook_invalid_subject(self): # TODO(@azharichenko): Added better subject verification in future update - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=200) - self.assertRaises(ValueError, textbook.get_textbook, TERM, 'Computer Science', '000', 'EXIST', None) + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=200 + ) + self.assertRaises(ValueError, textbook.get_textbook, TERM, "Computer Science", "000", "EXIST", None) @responses.activate def test_get_textbook_invalid_instructor(self): - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=200) - self.assertRaises(LookupError, textbook.get_textbook, TERM, 'CS', '447', 'EXIST', None) + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=200 + ) + self.assertRaises(LookupError, textbook.get_textbook, TERM, "CS", "447", "EXIST", None) @responses.activate def test_get_textbook_invalid_section(self): - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=200) - self.assertRaises(LookupError, textbook.get_textbook, TERM, 'CS', '401', None, '9999') + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=200 + ) + self.assertRaises(LookupError, textbook.get_textbook, TERM, "CS", "401", None, "9999") @responses.activate def test_get_textbook_invalid_section_and_instructor(self): - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=200) - self.assertRaises(TypeError, textbook.get_textbook, TERM, 'CS', '401', None, None) - + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=200 + ) + self.assertRaises(TypeError, textbook.get_textbook, TERM, "CS", "401", None, None) def test_term_validation(self): self.assertEqual(self.validate_term(TERM), TERM) def test_term_validation_invalid(self): - self.assertRaises(ValueError, self.validate_term, '1') - self.assertRaises(ValueError, self.validate_term, 'a') - self.assertRaises(ValueError, self.validate_term, '100') - self.assertRaises(ValueError, self.validate_term, '10000') + self.assertRaises(ValueError, self.validate_term, "1") + self.assertRaises(ValueError, self.validate_term, "a") + self.assertRaises(ValueError, self.validate_term, "100") + self.assertRaises(ValueError, self.validate_term, "10000") def test_validate_course_correct_input(self): - self.assertEqual(self.validate_course('0000'), '0000') - self.assertEqual(self.validate_course('0001'), '0001') - self.assertEqual(self.validate_course('0012'), '0012') - self.assertEqual(self.validate_course('0123'), '0123') - self.assertEqual(self.validate_course('1234'), '1234') - self.assertEqual(self.validate_course('9999'), '9999') + self.assertEqual(self.validate_course("0000"), "0000") + self.assertEqual(self.validate_course("0001"), "0001") + self.assertEqual(self.validate_course("0012"), "0012") + self.assertEqual(self.validate_course("0123"), "0123") + self.assertEqual(self.validate_course("1234"), "1234") + self.assertEqual(self.validate_course("9999"), "9999") def test_validate_course_improper_input(self): - self.assertEqual(self.validate_course('0'), '0000') - self.assertEqual(self.validate_course('1'), '0001') - self.assertEqual(self.validate_course('12'), '0012') - self.assertEqual(self.validate_course('123'), '0123') + self.assertEqual(self.validate_course("0"), "0000") + self.assertEqual(self.validate_course("1"), "0001") + self.assertEqual(self.validate_course("12"), "0012") + self.assertEqual(self.validate_course("123"), "0123") def test_validate_course_incorrect_input(self): - self.assertRaises(ValueError, self.validate_course, '') - self.assertRaises(ValueError, self.validate_course, '00000') - self.assertRaises(ValueError, self.validate_course, '11111') - self.assertRaises(ValueError, self.validate_course, 'hi') + self.assertRaises(ValueError, self.validate_course, "") + self.assertRaises(ValueError, self.validate_course, "00000") + self.assertRaises(ValueError, self.validate_course, "11111") + self.assertRaises(ValueError, self.validate_course, "hi") def test_construct_query(self): construct = textbook._construct_query - course_query = 'compare/courses/?id=9999&term_id=1111' - book_query = 'compare/books?id=9999' + course_query = "compare/courses/?id=9999&term_id=1111" + book_query = "compare/books?id=9999" - self.assertEqual(construct('courses', '9999', '1111'), course_query) - self.assertEqual(construct('books', '9999'), book_query) + self.assertEqual(construct("courses", "9999", "1111"), course_query) + self.assertEqual(construct("books", "9999"), book_query) def test_find_item(self): - find = textbook._find_item('id', 'key', 'test') - test_data = [ - {'id': 1, 'key': 1}, - {'id': 2, 'key': 4}, - {'id': 3, 'key': 9}, - {'id': 4, 'key': 16}, - {'id': 5, 'key': 25} - ] + find = textbook._find_item("id", "key", "test") + test_data = [{"id": 1, "key": 1}, {"id": 2, "key": 4}, {"id": 3, "key": 9}, {"id": 4, "key": 16}, {"id": 5, "key": 25}] for i in range(1, 6): - self.assertEqual(find(test_data, i), i ** 2) + self.assertEqual(find(test_data, i), i**2) self.assertRaises(LookupError, find, test_data, 6) @responses.activate def test_extract_id(self): - responses.add(responses.GET, 'http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000', - json=self.cs_data, status=201) - - def test_filter_dictionary(self): - test_dict = { - 'a': 1, - 'b': 2, - 'c': 3 - } - test_key = ['a', 'c'] - self.assertEqual( - textbook._filter_dictionary( - test_dict, test_key), {'a': 1, 'c': 3} + responses.add( + responses.GET, "http://pitt.verbacompare.com/compare/courses/?id=22457&term_id=1000", json=self.cs_data, status=201 ) - - + def test_filter_dictionary(self): + test_dict = {"a": 1, "b": 2, "c": 3} + test_key = ["a", "c"] + self.assertEqual(textbook._filter_dictionary(test_dict, test_key), {"a": 1, "c": 3}) def test_invalid_department_code(self): - self.assertRaises(ValueError, textbook.get_textbook, TERM, 'TEST', '000', 'EXIST', None) + self.assertRaises(ValueError, textbook.get_textbook, TERM, "TEST", "000", "EXIST", None)