diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cfe4ef0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,71 @@ +# push will run on every pushed commit to any branch (so this will rerun the tests +# once a branch gets merged to main in addition to any new commits on any branch) +on: push + +name: CI + +concurrency: + group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' + cancel-in-progress: true + +jobs: + Security: + name: Security Pipeline + uses: uc-cdis/.github/.github/workflows/securitypipeline.yaml@master + with: + python-poetry: 'true' + secrets: inherit + UnitTest: + name: Python Unit Test with Postgres + uses: uc-cdis/.github/.github/workflows/python_unit_test.yaml@master + with: + python-version: '3.9' + use-cache: true + + # this creates linter settings and uploads to an artifact so the configs can be pulled and used across jobs + LintConfig: + name: Get Lint Config + uses: uc-cdis/.github/.github/workflows/lint-create-config.yaml@master + with: + python-module-name: "cdislogging" + + # # (optional) modify the linter configurations from above. You could omit this if you didn't need to do this + # CustomizeLintConfig: + # runs-on: ubuntu-latest + # name: Customize Lint Config + # needs: [LintConfig] + # steps: + # - uses: actions/download-artifact@v3 + # with: + # # this is uploaded by the lint-create-config.yaml workflow + # name: linters-config + # path: .github/linters + # + # # modify default isort to specify the module name for proper formatting + # - run: echo "known_first_party=gen3userdatalibrary" >> .github/linters/.isort.cfg + # + # # now we need to re-upload the artifacts with the changes + # - uses: actions/upload-artifact@v3 + # with: + # name: linters-config + # path: | + # .github/linters/ + # if-no-files-found: error +# TODO: Uncomment after repo is public + + + RequiredLint: + name: Run Required Linters + needs: [ LintConfig ] + uses: uc-cdis/.github/.github/workflows/required_lint_check.yaml@master + with: + python-version: '3.9' + use-cache: true + InformationalLint: + name: Run Informational Linters + needs: [ LintConfig ] #TODO Add UnitTest + if: github.ref != 'refs/heads/main' + uses: uc-cdis/.github/.github/workflows/optional_lint_check.yaml@master + with: + python-version: '3.9' + use-cache: true diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml new file mode 100644 index 0000000..5a45f71 --- /dev/null +++ b/.github/workflows/pypi.yml @@ -0,0 +1,16 @@ +name: PyPI +on: + push: + tags: + - '*' +jobs: + PyPIPoetryPublish: + name: PyPI Poetry Publish + uses: uc-cdis/.github/.github/workflows/python_package_index_publish.yaml@master + with: + PYTHON_VERSION: '3.9' + # This will attempt push to test PyPI first and only push to prod if it works + DO_TEST_PUBLISH_FIRST: true + secrets: + PYPI_TEST_API_TOKEN: ${{ secrets.PYPI_TEST_API_TOKEN }} + PYPI_PROD_API_TOKEN: ${{ secrets.PYPI_PROD_API_TOKEN }} diff --git a/.github/workflows/wool.yaml b/.github/workflows/wool.yaml new file mode 100644 index 0000000..761b444 --- /dev/null +++ b/.github/workflows/wool.yaml @@ -0,0 +1,15 @@ +on: + pull_request + +name: Wool + +jobs: + runWool: + name: Run black + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + + - uses: uc-cdis/wool@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1647568..7b3ad91 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: git@github.com:Yelp/detect-secrets - rev: v0.13.1 + rev: v1.4.0 hooks: - id: detect-secrets args: ['--baseline', '.secrets.baseline'] @@ -13,6 +13,6 @@ repos: - id: no-commit-to-branch args: [--branch, develop, --branch, master, --branch, main, --pattern, release/.*] - repo: https://github.com/psf/black - rev: 20.8b1 + rev: 23.3.0 hooks: - id: black diff --git a/.secrets.baseline b/.secrets.baseline index edc74fd..420bc2f 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -1,19 +1,18 @@ { - "exclude": { - "files": ".lock", - "lines": null - }, - "generated_at": "2020-10-26T20:51:00Z", + "version": "1.4.0", "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, { "name": "AWSKeyDetector" }, { - "name": "ArtifactoryDetector" + "name": "AzureStorageKeyDetector" }, { - "base64_limit": 4.5, - "name": "Base64HighEntropyString" + "name": "Base64HighEntropyString", + "limit": 4.5 }, { "name": "BasicAuthDetector" @@ -22,8 +21,14 @@ "name": "CloudantDetector" }, { - "hex_limit": 3, - "name": "HexHighEntropyString" + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 }, { "name": "IbmCloudIamDetector" @@ -35,21 +40,30 @@ "name": "JwtTokenDetector" }, { - "keyword_exclude": null, - "name": "KeywordDetector" + "name": "KeywordDetector", + "keyword_exclude": "" }, { "name": "MailchimpDetector" }, + { + "name": "NpmDetector" + }, { "name": "PrivateKeyDetector" }, + { + "name": "SendGridDetector" + }, { "name": "SlackDetector" }, { "name": "SoftlayerDetector" }, + { + "name": "SquareOAuthDetector" + }, { "name": "StripeDetector" }, @@ -57,19 +71,68 @@ "name": "TwilioKeyDetector" } ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + } + ], "results": { + ".github/workflows/ci.yml": [ + { + "type": "Secret Keyword", + "filename": ".github/workflows/ci.yml", + "hashed_secret": "3e26d6750975d678acb8fa35a0f69237881576b0", + "is_verified": false, + "line_number": 17 + } + ], ".travis.yml": [ { + "type": "Base64 High Entropy String", + "filename": ".travis.yml", "hashed_secret": "5e82431714e70b91ba45fb02ac5b0f71d2e287a0", "is_verified": false, - "line_number": 27, - "type": "Base64 High Entropy String" + "line_number": 26 + }, + { + "type": "Base64 High Entropy String", + "filename": ".travis.yml", + "hashed_secret": "ea0ba5e253d998709fb91d850c1fc1c4674642d0", + "is_verified": false, + "line_number": 30 } ] }, - "version": "0.13.1", - "word_list": { - "file": null, - "hash": null - } + "generated_at": "2025-02-14T20:30:33Z" } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f596af0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,33 +0,0 @@ -language: python -dist: xenial -python: -- 3.5 -- 3.6 -- 3.7 -install: -- pip install pipenv -- pipenv install --dev --skip-lock --python `which python` -- pipenv graph -script: pipenv run py.test -v -before_deploy: -- sed -i.bak "s/=get_version()/='$TRAVIS_TAG'/g" setup.py -- cat setup.py -- if [ $(python setup.py --version) == '0.0.0' ]; then travis_terminate 1; fi -deploy: - provider: pypi - user: uc-ctds - skip_existing: true - skip_cleanup: true - on: - python: 3.6 - repo: uc-cdis/cdislogging - tags: true - password: - secure: o3Nizw9Jjbf2SBA2kE+7e08ZW0YTbshmYXHTS3+YAedfBlFyj78tH6+O3mnuWFsbNJKhMMwLYdOX0CMtVPjXg91wWyxZT9OLTCUqNYq9+K69ruDyJHM7QWKsLmLqCe4xVMQYxvlpJkZHHprfF3wXI9v3s0OV+Z+bAf9cAvW/dCcrXPsmRKeg94Whjj+MCDY58IG8mPIAvEMOoX6LEVqZVwagLGaIxkcQCbt+Zp8O72l3puex+x9wiqF0XawD3JdIMr7xf/xoEhuG7w697rnvHCEjW/48yKPXMwt/9/OV1ZQI3PVb6QxxsMAHB8UvQS/h4DtCh8OfZwchxB6MUwilnXHQjMd+diGCjOkk9G0ZBJuYb/Az9Z6YRGF+22qmcPC84KwOMoAY21sPQIuPHNDdug+HBXq07E5ZLmjBUvjVADN3ooLpXHswlOm3tYsnbStZox1+lqxCm2Z2f5v/Mz4C1IfWxtHFmM4U5UkDTQOu0K/C3NvEneKJrsN5Bd0/Cj1se3HYJgAhH0K1US5m8H7Vgejr9vIVSapa4QcTn3ZbeW/m1df2JXGG5cammbxXKxN4ErZq51j5hmp3yIL7H0Ohjnb9eTvsWDVtFL8FwrR8YbCFndF/2bsLlu860NTjaIz0P3pLizpd7hUZgh4+BCtvrt30x/HaelSmphja07EdlIg= -env: - global: - - PIPENV_IGNORE_VIRTUALENVS=1 - - secure: uovNV8i+Ef7EbSGaeGKvlm168nsuP6XF6p/ERlRQZtZ9HQBF14IVlqYnLgBvFGVdFsIc1mCroKqfdIiJIy75Bx1YOvO+u/3mxjMlOxuqxNCbIK0bYxZhrLqbR1oXGk6yPALpaeBdtuf43tnux0Ajk4URg2mIfqySkVldQPzL5XUfH/ueIruz6y5/alt7+c1Uj7HblGVBJbHx6JKGJSjpknfJyZXirw/lXpcFgOmRFjijGo4vYqmHIppGhERCCLNXdOTbrqe5dnbb8AD2AZwRDkgluYAYWaaJr9VosKzqD1lUfBVAbV91noCb+Nf91wfhzZemRWSy0xgIAPrpaT5QUm1OtJ1Z9J7yjD7Ljlt+CT5xHOE1uquKRXKzWpv4q1lHGyqyePKKHIcslu4gu1H8BO1EF212doQJFuPE68xEuSrVpZ0r2EKIYCgGfuto3AXWQzriD9uBQpqaVCNVjUkRVTa8t8G4WVLr3SeYSsY97CNASShJ9QiAshPogPv+FA+JM4JL0gyfrSCsaW2YtU1ovFv0ppP9KHtWzIZPEqZdMI8EUK4ugse94c2inzRJCTmE8j2K2J9sZS9i0jhTOnuL9mviXzr5goopmAYYhF1OWNV0KTDcxHnXSmWZR3HQP35aPFGZzjc0HLN/8khPb+P4mJ/XZfL+RtaQzJIYJ08TY6c= -after_deploy: -- pipenv run pip install gen3git -- pipenv run gen3git release diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 5ef121e..0000000 --- a/Pipfile +++ /dev/null @@ -1,11 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -pytest = "*" -mock = {version = "*",markers = "python_version<'3.0'"} - -[packages] -cdislogging = {path = ".",editable = true} diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 561ea1e..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,92 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "48d431e9db5c47945ed49a0cfc53cc7cb9e5ecd69f7ed31c2e79253cb5ebb20e" - }, - "pipfile-spec": 6, - "requires": {}, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "cdislogging": { - "editable": true, - "path": "." - } - }, - "develop": { - "atomicwrites": { - "hashes": [ - "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197", - "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a" - ], - "version": "==1.4.0" - }, - "attrs": { - "hashes": [ - "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", - "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700" - ], - "version": "==20.3.0" - }, - "mock": { - "hashes": [ - "sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1", - "sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba" - ], - "index": "pypi", - "markers": "python_version < '3.0'", - "version": "==2.0.0" - }, - "more-itertools": { - "hashes": [ - "sha256:5652a9ac72209ed7df8d9c15daf4e1aa0e3d2ccd3c87f8265a0673cd9cbc9ced", - "sha256:c5d6da9ca3ff65220c3bfd2a8db06d698f05d4d2b9be57e1deb2be5a45019713" - ], - "markers": "python_version > '2.7'", - "version": "==8.7.0" - }, - "pbr": { - "hashes": [ - "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9", - "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00" - ], - "version": "==5.5.1" - }, - "pluggy": { - "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" - ], - "version": "==0.13.1" - }, - "py": { - "hashes": [ - "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", - "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" - ], - "index": "pypi", - "version": "==1.10.0" - }, - "pytest": { - "hashes": [ - "sha256:13c5e9fb5ec5179995e9357111ab089af350d788cbc944c628f3cde72285809b", - "sha256:f21d2f1fb8200830dcbb5d8ec466a9c9120e20d8b53c7585d180125cce1d297a" - ], - "index": "pypi", - "version": "==4.4.0" - }, - "six": { - "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "version": "==1.15.0" - } - } -} diff --git a/README.md b/README.md index 95a1bc3..650675a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # cdislogging + Logging routines to centralize format -Basic usage: ---- +## Basic usage + In the parent/root module: ```python @@ -11,7 +12,9 @@ from cdislogging import get_logger logger = get_logger('__name__', log_level='info') logger.info('Hello world!') ``` + In a child module: + ```python from cdislogging import get_logger @@ -28,8 +31,7 @@ The default `log_level` argument in `get_logger` is `NONE`, which means the defa See more about Python logging [here](https://docs.python.org/3/library/logging.html). -Optional parameters: ---- +### Optional parameters * file_name (default: None) - If present, the logger will output logs to a file as well as stdout * log_level (default: 'debug') - Change the log level diff --git a/cdislogging/__init__.py b/cdislogging/__init__.py index f249333..0932394 100644 --- a/cdislogging/__init__.py +++ b/cdislogging/__init__.py @@ -6,7 +6,6 @@ import logging import sys - FORMAT = "[%(asctime)s][%(name)10s][%(levelname)7s] %(message)s" @@ -25,7 +24,7 @@ def get_stream_handler(format=FORMAT): return handler -def get_file_handler(file_name, format=FORMAT): +def get_file_handler(file_name: str, format=FORMAT): """Return a file handler Args: @@ -85,9 +84,8 @@ def get_logger(logger_name, file_name=None, log_level=None, format=FORMAT): if log_level: if log_level not in log_levels: error_message = ( - "Invalid log_level parameter: {}\n\n" - "Valid options: debug, info, warning, " - "warn, error".format(log_level) + f"Invalid log_level parameter: {log_level}\n\n" + "Valid options: debug, info, warn, warning, error" ) raise Exception(error_message) diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..adbbea3 --- /dev/null +++ b/clean.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +echo ---------------------------------------------- +echo Running isort to automatically sort imports +echo ---------------------------------------------- +echo Command: isort "$SCRIPT_DIR" --settings ~/.gen3/.github/.github/linters +isort "$SCRIPT_DIR" --settings ~/.gen3/.github/.github/linters +echo +echo ---------------------------------------------- +echo Running black to automatically format Python +echo ---------------------------------------------- +echo Command: black "$SCRIPT_DIR" --config ~/.gen3/.github/.github/linters/.python-black +black "$SCRIPT_DIR" --config ~/.gen3/.github/.github/linters/.python-black +echo +echo ---------------------------------------------- +echo Running pylint to detect lint +echo ---------------------------------------------- +echo Command: pylint -vv "$SCRIPT_DIR/cdislogging" --rcfile ~/.gen3/.github/linters/.python-lint +pylint -vv "$SCRIPT_DIR/cdislogging" --rcfile ~/.gen3/.github/.github/linters/.python-lint diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..487ffb6 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,484 @@ +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. + +[[package]] +name = "astroid" +version = "3.3.8" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "astroid-3.3.8-py3-none-any.whl", hash = "sha256:187ccc0c248bfbba564826c26f070494f7bc964fd286b6d9fff4420e55de828c"}, + {file = "astroid-3.3.8.tar.gz", hash = "sha256:a88c7994f914a4ea8572fac479459f4955eeccc877be3f2d959a33273b0cf40b"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "black" +version = "25.1.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, + {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, + {file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"}, + {file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"}, + {file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"}, + {file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"}, + {file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"}, + {file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"}, + {file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"}, + {file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"}, + {file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"}, + {file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"}, + {file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"}, + {file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"}, + {file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"}, + {file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"}, + {file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"}, + {file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"}, + {file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"}, + {file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"}, + {file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"}, + {file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.6.12" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, + {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, + {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, + {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, + {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, + {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, + {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, + {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, + {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, + {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, + {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, + {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, + {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, + {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, + {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, + {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, + {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, + {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, + {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, + {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, + {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, + {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, + {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, + {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, + {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, + {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, + {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, + {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, + {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, + {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, + {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, + {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, + {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, + {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, +] + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "dill" +version = "0.3.9" +description = "serialize all of Python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "6.0.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "isort-6.0.0-py3-none-any.whl", hash = "sha256:567954102bb47bb12e0fae62606570faacddd441e45683968c8d1734fb1af892"}, + {file = "isort-6.0.0.tar.gz", hash = "sha256:75d9d8a1438a9432a7d7b54f2d3b45cad9a4a0fdba43617d9873379704a8bdf1"}, +] + +[package.extras] +colors = ["colorama"] +plugins = ["setuptools"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mock" +version = "5.1.0" +description = "Rolling backport of unittest.mock for all Pythons" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "mock-5.1.0-py3-none-any.whl", hash = "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744"}, + {file = "mock-5.1.0.tar.gz", hash = "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d"}, +] + +[package.extras] +build = ["blurb", "twine", "wheel"] +docs = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pylint" +version = "3.3.4" +description = "python code static checker" +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "pylint-3.3.4-py3-none-any.whl", hash = "sha256:289e6a1eb27b453b08436478391a48cd53bb0efb824873f949e709350f3de018"}, + {file = "pylint-3.3.4.tar.gz", hash = "sha256:74ae7a38b177e69a9b525d0794bd8183820bfa7eb68cc1bee6e8ed22a42be4ce"}, +] + +[package.dependencies] +astroid = ">=3.3.8,<=3.4.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, +] +isort = ">=4.2.5,<5.13.0 || >5.13.0,<7" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pytest" +version = "8.3.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "2.12.1" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["dev"] +files = [ + {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, + {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, +] + +[package.dependencies] +coverage = ">=5.2.1" +pytest = ">=4.6" +toml = "*" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["dev"] +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.2" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.9,<4.0" +content-hash = "760739e96feb2dddd79d6467b78af46f09b151cc2ea9f9eb1acc964b91eed2e0" diff --git a/pull_request_template.md b/pull_request_template.md deleted file mode 100644 index 0cf7d01..0000000 --- a/pull_request_template.md +++ /dev/null @@ -1,28 +0,0 @@ - - -- [ ] Describe what this pull request does. -- [ ] Make sure all tests pass. -- [ ] Maintain or increase test coverage. -- [ ] Black the code. -- [ ] Test manually. -- [ ] Remove empty sections below. - -### New Features -- Implemented XXX - -### Breaking Changes - - -### Bug Fixes - - -### Improvements - - -### Dependency updates - - -### Deployment changes diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..872ed9b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[tool.poetry] +name = "cdislogging" +version = "1.1.2" +description = "Logging routines with centralized format" +authors = ["Center for Translational Data Science at the University of Chicago "] +license = "Apache-2.0" +readme = "README.md" +repository = "https://github.com/uc-cdis/cdislogging" +include = [ + "NOTICE", +] + +[tool.poetry.dependencies] +python = ">=3.9,<4.0" + +[tool.poetry.group.dev.dependencies] +mock = "*" +pytest = "*" +pytest-cov = "^2.5.1" +isort = ">=5.12.0" +pylint = ">=3.0.1" +black = ">=23.10.0" + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/release_notes.sh b/release_notes.sh deleted file mode 100755 index 42df849..0000000 --- a/release_notes.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -pip install git+https://github.com/uc-cdis/release-helper.git@master#egg=gen3git -gen3git --repo $TRAVIS_REPO_SLUG --from-tag $(git describe --tags --abbrev=0 --match=[0-9]* --exclude=$TRAVIS_TAG) gen --text --markdown --to-tag $TRAVIS_TAG -URL=$(curl -s -H "Authorization:token $GH_TOKEN" https://api.github.com/repos/${TRAVIS_REPO_SLUG}/releases/tags/$TRAVIS_TAG | python -c "import sys, json; print(json.load(sys.stdin)['url'])") -echo $URL -if [[ $URL ]]; then - curl -H "Authorization: token $GH_TOKEN" --request PATCH $URL --data "$(python -c "import sys,json; json.dump(dict(body=open('release_notes.md').read()), sys.stdout)")" -fi diff --git a/setup.py b/setup.py deleted file mode 100644 index 44b1ca9..0000000 --- a/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -from subprocess import check_output - -from setuptools import setup, find_packages - - -def get_version(): - # https://github.com/uc-cdis/dictionaryutils/pull/37#discussion_r257898408 - try: - tag = check_output( - ["git", "describe", "--tags", "--abbrev=0", "--match=[0-9]*"] - ) - return tag.decode("utf-8").strip("\n") - except Exception: - raise RuntimeError( - "The version number cannot be extracted from git tag in this source " - "distribution; please either download the source from PyPI, or check out " - "from GitHub and make sure that the git CLI is available." - ) - - -setup( - name="cdislogging", - version=get_version(), - description="Standardized logging tool and format for cdis applications", - license="Apache", - packages=find_packages(), -) diff --git a/tests/test_logging.py b/tests/test_logging.py index 2b577e6..3d53f81 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -1,20 +1,10 @@ -"""tests/test_logging.py +"""Basic set of tests for logging""" -Basic set of tests for logging -""" - -import os import logging +import os +from unittest.mock import MagicMock -import pytest - -# Python 2 and 3 compatible -try: - from unittest.mock import MagicMock - from unittest.mock import patch -except ImportError: - from mock import MagicMock - from mock import patch +import pytest # pylint: disable=E0401 import cdislogging @@ -29,14 +19,20 @@ def delete_loggers(): def test_get_stream_handler(): + """Test get_stream_handler""" handler = cdislogging.get_stream_handler() - assert handler.formatter._fmt == cdislogging.FORMAT + assert ( + handler.formatter._fmt == cdislogging.FORMAT # pylint: disable=protected-access + ) def test_get_file_handler(): + """Test get_file_handler""" file_name = "FAKE-LOGGER.TXT" handler = cdislogging.get_file_handler(file_name) - assert handler.formatter._fmt == cdislogging.FORMAT + assert ( + handler.formatter._fmt == cdislogging.FORMAT # pylint: disable=protected-access + ) assert os.path.basename(handler.stream.name) == file_name assert os.path.exists(file_name) @@ -46,6 +42,7 @@ def test_get_file_handler(): def test_get_logger(): + """Test get_logger""" log_name = "test_get_logger" logger = cdislogging.get_logger(log_name) assert logger.name == log_name @@ -62,6 +59,7 @@ def test_get_logger(): @pytest.mark.parametrize("given,expected", log_levels) def test_get_logger_log_levels(given, expected): + """Test get_logger_log_levels""" logger = cdislogging.get_logger( "test_get_logger_log_levels" + given, log_level=given ) @@ -69,6 +67,7 @@ def test_get_logger_log_levels(given, expected): def test_multiple_log_handlers(): + """Test multiple log handlers""" logger = cdislogging.get_logger("one_handler", log_level="debug") assert len(logger.handlers) == 1 @@ -84,7 +83,7 @@ def test_instantiate_with_log_level(): """ logger = cdislogging.get_logger("logger", log_level="info") assert logger.level == logging.INFO - assert logger.propagate == False + assert logger.propagate is False assert len(logger.handlers) == 1 @@ -95,7 +94,7 @@ def test_instantiate_without_log_level(): """ logger = cdislogging.get_logger("logger") assert logger.level == logging.NOTSET - assert logger.propagate == True + assert logger.propagate is True assert len(logger.handlers) == 0 @@ -173,15 +172,14 @@ def test_child_change_level_from_notset_updates_properties(): the child logger correctly updates level and propagate, and gets its own handler """ - parent = cdislogging.get_logger("parent", log_level="info") child = cdislogging.get_logger("parent.child") - assert child.propagate == True + assert child.propagate is True assert len(child.handlers) == 0 # TODO: should really rename this to get_or_update_logger... cdislogging.get_logger("parent.child", log_level="warn") - assert child.propagate == False + assert child.propagate is False assert len(child.handlers) == 1 @@ -202,7 +200,9 @@ def test_child_change_level_from_notset_logs_own_level(): mock_child_hdlr_emit = MagicMock() child.handlers[0].emit = mock_child_hdlr_emit - child.warn("Should emit with child hdlr only; child no longer inherits/propagates") + child.warning( + "Should emit with child hdlr only; child no longer inherits/propagates" + ) assert mock_parent_hdlr_emit.call_count == 0 assert mock_child_hdlr_emit.call_count == 1 @@ -211,39 +211,15 @@ def test_child_change_level_from_notset_logs_own_level(): assert mock_child_hdlr_emit.call_count == 1 -def test_reset_to_notset(): - """ - Check that if logger was instantiated with log_level != NOTSET - and then get_logger() is called on it again with log_level='notset', - the logger's log level is correctly reset to NOTSET - and the logger logs at the correct level - """ - parent = cdislogging.get_logger("parent", log_level="debug") - mock_parent_hdlr_emit = MagicMock() - parent.handlers[0].emit = mock_parent_hdlr_emit - - child = cdislogging.get_logger("parent.child", log_level="info") - mock_child_hdlr_emit = MagicMock() - child.handlers[0].emit = mock_child_hdlr_emit - - child = cdislogging.get_logger("parent.child", log_level="notset") - assert child.propagate == True - assert len(child.handlers) == 0 - - child.info("Should emit with parent hdlr only") - assert mock_parent_hdlr_emit.call_count == 1 - assert mock_child_hdlr_emit.call_count == 0 - - child.debug("Should emit with parent hdlr only") - assert mock_parent_hdlr_emit.call_count == 2 - assert mock_child_hdlr_emit.call_count == 0 - - -def test_no_unintentional_reset_to_notset(): +def test_no_reset_and_reset_to_notset(): """ Check that if logger was instantiated with log_level != NOTSET and then get_logger() is called on it again without a log_level arg, the logger's log level does _not_ get reset to NOTSET + + Then check if get_logger() is called on it again with log_level='notset', + the logger's log level is correctly reset to NOTSET + and the logger logs at the correct level """ parent = cdislogging.get_logger("parent", log_level="debug") mock_parent_hdlr_emit = MagicMock() @@ -257,10 +233,26 @@ def test_no_unintentional_reset_to_notset(): assert mock_parent_hdlr_emit.call_count == 0 assert mock_child_hdlr_emit.call_count == 1 + # get_logger() is called on it again without a log_level arg, child = cdislogging.get_logger("parent.child") child.debug( "Should not emit, but will emit on parent hdlr if child level was reset to NOTSET" ) - + # the logger's log level does _not_ get reset to NOTSET assert mock_parent_hdlr_emit.call_count == 0 assert mock_child_hdlr_emit.call_count == 1 + + # get_logger() is called on it again with log_level='notset', + child = cdislogging.get_logger("parent.child", log_level="notset") + assert child.propagate is True + assert len(child.handlers) == 0 + + # the logger's log level is correctly reset to NOTSET + # and the logger logs at the correct level (ie, parent) + child.info("Should emit with parent hdlr only") + assert mock_parent_hdlr_emit.call_count == 1 + assert mock_child_hdlr_emit.call_count == 1 + + child.debug("Should emit with parent hdlr only") + assert mock_parent_hdlr_emit.call_count == 2 + assert mock_child_hdlr_emit.call_count == 1