diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..32a5fca --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[run] +omit = test/*.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..9390eba --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,52 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + workflow_dispatch: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +permissions: # added using https://github.com/step-security/secure-repo + contents: read +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Harden Runner + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + with: + egress-policy: audit + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Set up Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + with: + python-version: '3.x' + - name: Install poetry + uses: abatilo/actions-poetry@e78f54a89cb052fff327414dd9ff010b5d2b4dbd # v3.0.1 + - name: Run tests + run: | + poetry install --with test + poetry run coverage run --branch -m unittest discover -b + poetry run coverage xml + - name: Save debug.log file + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + if: always() + with: + name: debug-log + path: ./debug.log + - name: SonarCloud Scan + uses: SonarSource/sonarcloud-github-action@383f7e52eae3ab0510c3cb0e7d9d150bbaeab838 # master + continue-on-error: true # added since if it's a PR from a different user account, the credentials won't pass over + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/lfx_tac_actions/updateclomonitor.py b/lfx_tac_actions/updateclomonitor.py index e9d9197..7acaf9d 100755 --- a/lfx_tac_actions/updateclomonitor.py +++ b/lfx_tac_actions/updateclomonitor.py @@ -7,7 +7,7 @@ import yaml import argparse -import urllib.request +import requests import urllib.parse import json import os @@ -17,12 +17,12 @@ def main(): parser.add_argument("-o", "--output", help="filename to save output to",default='_data/clomonitor.yaml') args = parser.parse_args() - if os.environ.get("LANDSCAPE_URL") != '' and os.environ.get("ARTWORK_URL") != '': + if os.environ.get("LANDSCAPE_URL") != '': landscape_hosted_projects = '{}/api/projects/all.json'.format(os.environ.get("LANDSCAPE_URL")) project_entries = [] - with urllib.request.urlopen(landscape_hosted_projects) as hosted_projects_response: - project_data = json.load(hosted_projects_response) + with requests.get(landscape_hosted_projects) as hosted_projects_response: + project_data = hosted_projects_response.json() for project in project_data: if project.get('maturity') == 'emeritus': continue @@ -33,8 +33,8 @@ def main(): logo_url_dark = '' if project.get('artwork_url'): urlparts = urllib.parse.urlparse(project.get('artwork_url')) - with urllib.request.urlopen('{}://{}/assets/data.json'.format(urlparts.scheme,urlparts.netloc)) as artwork_response: - artwork_data = json.load(artwork_response) + with requests.get('{}://{}/assets/data.json'.format(urlparts.scheme,urlparts.netloc)) as artwork_response: + artwork_data = artwork_response.json() logo_url = '{}://{}{}{}'.format(urlparts.scheme,urlparts.netloc,urlparts.path,artwork_data.get(urlparts.path,{}).get('primary_logo')) logo_url_dark = '{}://{}{}{}'.format(urlparts.scheme,urlparts.netloc,urlparts.path,artwork_data.get(urlparts.path,{}).get('dark_logo')) else: @@ -60,9 +60,9 @@ def main(): }) project_entries.append(project_entry) - with open(args.output, 'w') as clomonitor_file_object: - print("Saving file {}".format(args.output)) - yaml.dump(project_entries, clomonitor_file_object, sort_keys=False, indent=2) + with open(args.output, 'w') as clomonitor_file_object: + print("Saving file {}".format(args.output)) + yaml.dump(project_entries, clomonitor_file_object, sort_keys=False, indent=2) if __name__ == '__main__': main() diff --git a/lfx_tac_actions/updateprojects.py b/lfx_tac_actions/updateprojects.py index d113a3b..1cd6eef 100755 --- a/lfx_tac_actions/updateprojects.py +++ b/lfx_tac_actions/updateprojects.py @@ -6,7 +6,7 @@ # encoding=utf8 import csv -import urllib.request +import requests import json import os import argparse @@ -20,8 +20,8 @@ def main(): landscape_hosted_projects = '{}/api/projects/all.json'.format(os.environ["LANDSCAPE_URL"]) csv_rows = [] - with urllib.request.urlopen(landscape_hosted_projects) as hosted_projects_response: - project_data = json.load(hosted_projects_response) + with requests.get(landscape_hosted_projects) as hosted_projects_response: + project_data = hosted_projects_response.json() for project in project_data: categories = [] categories.append("{category} / {subcategory}".format(category=project.get('category'),subcategory=project.get('subcategory'))) diff --git a/lfx_tac_actions/updatetacmembers.py b/lfx_tac_actions/updatetacmembers.py index 31d5275..a063a36 100755 --- a/lfx_tac_actions/updatetacmembers.py +++ b/lfx_tac_actions/updatetacmembers.py @@ -7,7 +7,7 @@ import argparse import csv -import urllib.request +import requests import json import os from urllib.parse import urlparse @@ -23,8 +23,8 @@ def main(): committee_url = 'https://api-gw.platform.linuxfoundation.org/project-service/v2/public/projects/{project_id}/committees/{committee_id}/members'.format(project_id=urlparts[2],committee_id=urlparts[5]) csv_rows = [] - with urllib.request.urlopen(committee_url) as committee_url_response: - committee_url_response_json = json.load(committee_url_response) + with requests.get(committee_url) as committee_url_response: + committee_url_response_json = committee_url_response.json() for committee_member in committee_url_response_json.get('Data',[]): print("Processing {} {}...".format(committee_member.get('FirstName').title(),committee_member.get('LastName').title())) csv_rows.append({ diff --git a/poetry.lock b/poetry.lock index 395a147..e6f6ca8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,218 @@ # This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +[[package]] +name = "certifi" +version = "2024.8.30" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +] + +[[package]] +name = "coverage" +version = "7.6.8" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "coverage-7.6.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50"}, + {file = "coverage-7.6.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed"}, + {file = "coverage-7.6.8-cp310-cp310-win32.whl", hash = "sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e"}, + {file = "coverage-7.6.8-cp310-cp310-win_amd64.whl", hash = "sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0"}, + {file = "coverage-7.6.8-cp311-cp311-win32.whl", hash = "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801"}, + {file = "coverage-7.6.8-cp311-cp311-win_amd64.whl", hash = "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443"}, + {file = "coverage-7.6.8-cp312-cp312-win32.whl", hash = "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad"}, + {file = "coverage-7.6.8-cp312-cp312-win_amd64.whl", hash = "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b"}, + {file = "coverage-7.6.8-cp313-cp313-win32.whl", hash = "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146"}, + {file = "coverage-7.6.8-cp313-cp313-win_amd64.whl", hash = "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b"}, + {file = "coverage-7.6.8-cp313-cp313t-win32.whl", hash = "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71"}, + {file = "coverage-7.6.8-cp313-cp313t-win_amd64.whl", hash = "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea"}, + {file = "coverage-7.6.8-cp39-cp39-win32.whl", hash = "sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e"}, + {file = "coverage-7.6.8-cp39-cp39-win_amd64.whl", hash = "sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076"}, + {file = "coverage-7.6.8-pp39.pp310-none-any.whl", hash = "sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce"}, + {file = "coverage-7.6.8.tar.gz", hash = "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc"}, +] + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "pyyaml" version = "6.0.2" @@ -62,7 +275,64 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "responses" +version = "0.25.3" +description = "A utility library for mocking out the `requests` Python library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "responses-0.25.3-py3-none-any.whl", hash = "sha256:521efcbc82081ab8daa588e08f7e8a64ce79b91c39f6e62199b19159bea7dbcb"}, + {file = "responses-0.25.3.tar.gz", hash = "sha256:617b9247abd9ae28313d57a75880422d55ec63c29d33d629697590a034358dba"}, +] + +[package.dependencies] +pyyaml = "*" +requests = ">=2.30.0,<3.0" +urllib3 = ">=1.25.10,<3.0" + +[package.extras] +tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "tomli", "tomli-w", "types-PyYAML", "types-requests"] + +[[package]] +name = "urllib3" +version = "2.2.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "afb15bf55b7b161475831218b887c02269ba8428ba2de5012ee70a4e526691c1" +content-hash = "44751e2c944249c15153861a16bedc051cda6f1c3c7a2a78cf990b08ff2fd7d7" diff --git a/pyproject.toml b/pyproject.toml index a71f43f..079601d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,11 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.12" pyyaml = "^6.0.2" +requests = "^2.32.3" + +[tool.poetry.group.test.dependencies] +coverage = "^7.6.4" +responses = "^0.25.3" [tool.poetry.scripts] updateprojects = "lfx_tac_actions.updateprojects:main" diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..1350905 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,6 @@ +sonar.projectKey=jmertic_lfx-tac-actions +sonar.organization=jmertic +sonar.projectName=lfx-tac-actions +sonar.projectVersion=1.0 +sonar.sources=lfx_tac_actions +sonar.python.coverage.reportPaths=coverage.xml diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..7614b1b --- /dev/null +++ b/test/__init__.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +# +# Copyright this project and it's contributors +# SPDX-License-Identifier: Apache-2.0 +# +# encoding=utf8 + + diff --git a/test/test_updateclomonitor.py b/test/test_updateclomonitor.py new file mode 100644 index 0000000..45e5ec7 --- /dev/null +++ b/test/test_updateclomonitor.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# +# Copyright this project and it's contributors +# SPDX-License-Identifier: Apache-2.0 +# +# encoding=utf8 + +import unittest +import tempfile +import os +import responses +import argparse + +from lfx_tac_actions.updateclomonitor import main + +class TestUpdateCLOMonitor(unittest.TestCase): + + @unittest.mock.patch.dict(os.environ, {"LANDSCAPE_URL": ""}, clear=True) + def testMainNoLandscapeUrl(self): + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.yaml') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + self.assertFalse(os.path.exists(tmpfilepath), f"File '{tmpfilepath}' exists.") + + @responses.activate + @unittest.mock.patch.dict(os.environ, {"LANDSCAPE_URL": "https://landscape.aswf.io"}, clear=True) + def testMain(self): + responses.add( + method=responses.GET, + url="https://artwork.aswf.io/assets/data.json", + json={ + "/projects/opencolorio/": { + "name": "OpenColorIO", + "category": "Adopted Projects", + "primary_logo": "stacked/color/opencolorio-stacked-color.svg", + "dark_logo": "stacked/color/opencolorio-stacked-color.svg", + } + }) + responses.add( + method=responses.GET, + url="https://landscape.aswf.io/api/projects/all.json", + json=[ + { + "category": "ASWF Projects", + "homepage_url": "https://opencolorio.org/", + "id": "aswf-projects--all--opencolorio", + "logo_url": "https://aswf.landscape2.io/logos/2d4849a9c8ebf6d6e9e1096d191e88739c4abd47754620e7a1c5244ebe14aa05.svg", + "name": "OpenColorIO", + "subcategory": "All", + "accepted_at": "2020-04-24", + "additional_categories": [ + { + "category": "Imaging and Color", + "subcategory": "Color Science" + }, + { + "category": "Dev Days 2024", + "subcategory": "Participating Project" + } + ], + "annotations": { + "ical_url": "https://webcal.prod.itx.linuxfoundation.org/lfx/a092M00001If9v8QAB", + "slug": "opencolorio", + "chair": "Carol Payne", + "calendar_url": "https://zoom-lfx.platform.linuxfoundation.org/meetings/opencolorio", + "next_annual_review_date": "2025-01-22" + }, + "artwork_url": "https://artwork.aswf.io/projects/opencolorio/", + "country": "United States", + "crunchbase_url": "https://www.crunchbase.com/organization/academy-software-foundation", + "description": "The OpenColorIO project is committed to providing an industry standard solution for highly precise, performant, and consistent color management across digital content creation applications and pipelines.", + "devstats_url": "https://insights.lfx.linuxfoundation.org/foundation/aswf/overview?project=opencolorio", + "latest_annual_review_at": "2023-11-01", + "latest_annual_review_url": "https://github.com/AcademySoftwareFoundation/tac/issues/474", + "mailing_list_url": "https://lists.aswf.io/g/ocio-user", + "maturity": "adopted", + "oss": True, + "repositories": [ + { + "url": "https://github.com/AcademySoftwareFoundation/OpenColorIO", + "languages": { + "Batchfile": 26254, + "C": 61491, + "C++": 8288679, + "CMake": 286452, + "Java": 73341, + "Objective-C": 6826, + "Objective-C++": 37712, + "Python": 1268733, + "Roff": 867637, + "Shell": 19585 + }, + "primary": True + }, + { + "url": "https://github.com/AcademySoftwareFoundation/OpenColorIO-Config-ACES", + "languages": { + "Dockerfile": 1814, + "Python": 391928 + }, + "primary": False + } + ], + "slack_url": "https://slack.opencolorio.org" + } + ] + ) + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.yaml') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + + with open(tmpfilepath, 'r') as tmpfile: + self.maxDiff = None + self.assertEqual(tmpfile.read(),'''- name: opencolorio + display_name: OpenColorIO + description: The OpenColorIO project is committed to providing an industry standard + solution for highly precise, performant, and consistent color management across + digital content creation applications and pipelines. + category: Visual Effects and Computer Graphics + logo_url: https://artwork.aswf.io/projects/opencolorio/stacked/color/opencolorio-stacked-color.svg + logo_url_dark: https://artwork.aswf.io/projects/opencolorio/stacked/color/opencolorio-stacked-color.svg + devstats_url: null + maturity: adopted + repositories: + - name: OpenColorIO + url: https://github.com/AcademySoftwareFoundation/OpenColorIO + exclude: + - clomonitor + - name: OpenColorIO-Config-ACES + url: https://github.com/AcademySoftwareFoundation/OpenColorIO-Config-ACES + exclude: + - clomonitor +''') + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_updateprojects.py b/test/test_updateprojects.py new file mode 100644 index 0000000..a1f6a10 --- /dev/null +++ b/test/test_updateprojects.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# +# Copyright this project and it's contributors +# SPDX-License-Identifier: Apache-2.0 +# +# encoding=utf8 + +import unittest +import tempfile +import os +import responses +import argparse + +from lfx_tac_actions.updateprojects import main + +class TestUpdateProjects(unittest.TestCase): + + @unittest.mock.patch.dict(os.environ, {"LANDSCAPE_URL": ""}, clear=True) + def testMainNoLandscapeUrl(self): + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.csv') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + self.assertFalse(os.path.exists(tmpfilepath), f"File '{tmpfilepath}' exists.") + + @responses.activate + @unittest.mock.patch.dict(os.environ, {"LANDSCAPE_URL": "https://landscape.aswf.io"}, clear=True) + def testMain(self): + responses.add( + method=responses.GET, + url="https://landscape.aswf.io/api/projects/all.json", + json=[ + { + "category": "ASWF Projects", + "homepage_url": "https://github.com/vfx-rs", + "id": "aswf-projects--all--aswf-language-interop-project", + "logo_url": "https://aswf.landscape2.io/logos/803e21319d55195829c27a3bc448d43e8f14dbcf544e4d44418299df3a3cca61.svg", + "name": "ASWF Language Interop Project", + "subcategory": "All", + "accepted_at": "2023-10-20", + "additional_categories": [ + { + "category": "Math and Simulation", + "subcategory": "Math Foundations" + } + ], + "annotations": { + "slug": "aswf-language-interop-project", + "chair": "Scott Wilson", + "ical_url": "https://webcal.prod.itx.linuxfoundation.org/lfx/lfv8NMKI8tcp96N5tb", + "next_annual_review_date": "2025-03-19", + "calendar_url": "https://zoom-lfx.platform.linuxfoundation.org/meetings/aswf-language-interop-project" + }, + "artwork_url": "https://artwork.aswf.io/projects/aswf-language-interop-project/", + "chat_channel": "#rust", + "country": "United States", + "crunchbase_url": "https://www.crunchbase.com/organization/academy-software-foundation", + "description": "The mission of the Project is to enable interoperability between various programming languages across each of the libraries used by the media and entertainment industry.", + "devstats_url": "https://insights.lfx.linuxfoundation.org/foundation/aswf/overview?project=aswf-language-interop-project", + "latest_annual_review_at": "2024-03-20", + "latest_annual_review_url": "https://github.com/AcademySoftwareFoundation/tac/issues/489", + "mailing_list_url": "https://lists.aswf.io/g/wg-rust", + "maturity": "working-group", + "oss": True, + "repositories": [ + { + "url": "https://github.com/vfx-rs/organization", + "languages": { }, + "primary": True + } + ], + "slack_url": "https://slack.aswf.io" + } + ] + ) + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.csv') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + + with open(tmpfilepath, 'r') as tmpfile: + self.maxDiff = None + self.assertEqual(tmpfile.read(),'Name,Level,Logo URL,Slug,Categories,Website,Chair,TAC Representative,Documentation,Calendar,Artwork,iCal,LFX Insights URL,Accepted Date,Last Review Date,Next Review Date,Slack URL,Chat Channel,Mailing List,Github Org,Best Practices Badge ID,Primary Github Repo,Contributed By\nASWF Language Interop Project,working-group,https://aswf.landscape2.io/logos/803e21319d55195829c27a3bc448d43e8f14dbcf544e4d44418299df3a3cca61.svg,aswf-language-interop-project,"ASWF Projects / All,Math and Simulation / Math Foundations",https://github.com/vfx-rs,Scott Wilson,,,https://zoom-lfx.platform.linuxfoundation.org/meetings/aswf-language-interop-project,https://artwork.aswf.io/projects/aswf-language-interop-project/,https://webcal.prod.itx.linuxfoundation.org/lfx/lfv8NMKI8tcp96N5tb,,2023-10-20,,2025-03-19,https://slack.aswf.io,#rust,https://lists.aswf.io/g/wg-rust,,,,\n') + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_updatetacagendaitems.py b/test/test_updatetacagendaitems.py new file mode 100644 index 0000000..d07969d --- /dev/null +++ b/test/test_updatetacagendaitems.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Copyright this project and it's contributors +# SPDX-License-Identifier: Apache-2.0 +# +# encoding=utf8 + +import unittest +import tempfile +import os +import responses +import argparse + +from lfx_tac_actions.updatetacagendaitems import main + +class TestUpdateTACAgendaItems(unittest.TestCase): + + @unittest.mock.patch.dict(os.environ, {"TAC_AGENDA_GH_PROJECT_URL": ""}, clear=True) + def testMainNoLandscapeUrl(self): + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.csv') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + self.assertFalse(os.path.exists(tmpfilepath), f"File '{tmpfilepath}' exists.") + + @responses.activate + @unittest.mock.patch.dict(os.environ, {"TAC_AGENDA_GH_PROJECT_URL": "https://github.com/orgs/openmainframeproject/projects/21"}, clear=True) + @unittest.mock.patch('subprocess.run') + def testMain(self, mock_run): + mock_result = unittest.mock.Mock() + mock_result.stdout = '{"items":[{"assignees":["carolalynn"],"content":{"body":"","number":473,"repository":"AcademySoftwareFoundation/tac","title":"D&I Working Group","type":"Issue","url":"https://github.com/AcademySoftwareFoundation/tac/issues/473"},"id":"PVTI_lADOAm6tAs4AS_w4zgJSO7E","labels":["2-annual-review"],"landscape URL":"https://landscape.aswf.io/card-mode?project=working-group&selected=d-i-working-group","pCC Project ID":"a092M00001KWjDZQA1","pCC TSC Committee ID":"ac9cbe7f-0dc8-4be0-b404-cb7b9b0bb22f","repository":"https://github.com/AcademySoftwareFoundation/tac","scheduled Date":"2024-12-11","status":"Next Meeting Agenda Items","title":"D&I Working Group"}],"totalCount":32}' + mock_run.return_value = mock_result + + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.csv') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + + with open(tmpfilepath, 'r') as tmpfile: + self.maxDiff = None + self.assertEqual(tmpfile.read(),'''title,url,number,scheduled_date,status,last_review_date,meeting_label +D&I Working Group,https://github.com/AcademySoftwareFoundation/tac/issues/473,473,2024-12-11,Next Meeting Agenda Items,,2-annual-review +''') + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_updatetacmembers.py b/test/test_updatetacmembers.py new file mode 100644 index 0000000..1422dac --- /dev/null +++ b/test/test_updatetacmembers.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# +# Copyright this project and it's contributors +# SPDX-License-Identifier: Apache-2.0 +# +# encoding=utf8 + +import unittest +import tempfile +import os +import responses +import argparse + +from lfx_tac_actions.updatetacmembers import main + +class TestUpdateTACMembers(unittest.TestCase): + + @unittest.mock.patch.dict(os.environ, {"LFX_TAC_COMMITTEE_URL": ""}, clear=True) + def testMainNoLandscapeUrl(self): + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.csv') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + self.assertFalse(os.path.exists(tmpfilepath), f"File '{tmpfilepath}' exists.") + + @responses.activate + @unittest.mock.patch.dict(os.environ, {"LFX_TAC_COMMITTEE_URL": "https://projectadmin.lfx.linuxfoundation.org/project/a0941000002wBymAAE/collaboration/committees/163b26f7-a49b-40a3-89bb-e0592296c003"}, clear=True) + def testMain(self): + responses.add( + method=responses.GET, + url="https://api-gw.platform.linuxfoundation.org/project-service/v2/public/projects/a0941000002wBymAAE/committees/163b26f7-a49b-40a3-89bb-e0592296c003/members", + json={ + "Data": [ + { + "AppointedBy": "Vote of TSC Committee", + "FirstName": "Andrea", + "LastName": "Orth", + "Role": "None", + "Status": "Active", + "VotingStartDate": "2022-06-21", + "VotingStatus": "Voting Rep", + "MemberID": "0032M000032nKeAQAU", + "OrganizationID": "0014100000Te2cmAAB", + "AboutMe": { + "Description": "I've worked in IT for over 25 years at the same Fortune 50 company. I started out as a mainframe developer working with COBOL and DB2. Early in my career I worked with the GenevaERS product and came to understand the scalability and efficiency the mainframe provides. During my career, I've had had different roles including Scrum Master and Product Owner. \n\nI have served as the Vice Chair of the GenevaERS Technical Steering Committee sponsored by the Linux Foundation's Open Mainframe Project since the project's inception. Among other things, I have acted as Scrum Master, run communications for the project, provide customer input and direction, and provided an independent voice. I was recently appointed the Chair of the project.\n\nHobbies include collecting hobbies and caring for my over 30 pets.", + "GitHub": "https://github.com/AOrthVector", + "LinkedIn": "https://linkedin.com/in/andrea-orth" + }, + "CreatedDate": "2022-06-21T17:47:53.358Z", + "ID": "e48fee2b-9848-40e1-bb5b-4aa6e350e90e", + "LogoURL": "https://avatars0.githubusercontent.com/u/61636929?v=4", + "Organization": { + "ID": "0014100000Te2cmAAB", + "LogoURL": "https://lf-master-organization-logos-prod.s3.us-east-2.amazonaws.com/state-farm-mutual-insurance-company.svg", + "Name": "State Farm Mutual Automobile Insurance Company" + }, + "SystemModStamp": "2024-01-16T21:13:07.501Z", + "Title": "Scrum Master" + }, + ] + } + ) + with tempfile.TemporaryDirectory() as tempdir: + tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.csv') + with unittest.mock.patch('argparse.ArgumentParser.parse_args') as mock: + mock.return_value = argparse.Namespace(output=tmpfilepath) + main() + + with open(tmpfilepath, 'r') as tmpfile: + self.maxDiff = None + self.assertEqual(tmpfile.read(),'''Full Name,Account Name: Account Name,Appointed By,Voting Status,Special Role,Title,HeadshotURL\nAndrea Orth,State Farm Mutual Automobile Insurance Company,Vote of TSC Committee,Voting Rep,None,Scrum Master,https://avatars0.githubusercontent.com/u/61636929?v=4\n''') + +if __name__ == '__main__': + unittest.main()