diff --git a/.deprecated_files b/.deprecated_files index f539daad..2ac2e3e1 100644 --- a/.deprecated_files +++ b/.deprecated_files @@ -17,3 +17,6 @@ docs setup.py setup.cfg + +.pylintrc +.flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index bfd9ba41..00000000 --- a/.flake8 +++ /dev/null @@ -1,21 +0,0 @@ -; Copyright 2021 - 2023 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln -; for the German Human Genome-Phenome Archive (GHGA) -; -; Licensed under the Apache License, Version 2.0 (the "License"); -; you may not use this file except in compliance with the License. -; You may obtain a copy of the License at -; -; http://www.apache.org/licenses/LICENSE-2.0 -; -; Unless required by applicable law or agreed to in writing, software -; distributed under the License is distributed on an "AS IS" BASIS, -; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -; See the License for the specific language governing permissions and -; limitations under the License. - -[flake8] -ignore = E, W - # ignore all style checks from pycodestyle - # as they are already checked by black -exclude = .git,__pycache__,build,dist -max-complexity = 10 diff --git a/.github/workflows/static_code_analysis.yaml b/.github/workflows/static_code_analysis.yaml index aad3a45a..401f4289 100644 --- a/.github/workflows/static_code_analysis.yaml +++ b/.github/workflows/static_code_analysis.yaml @@ -15,24 +15,14 @@ jobs: - uses: pre-commit/action@v3.0.0 env: SKIP: no-commit-to-branch + - name: ruff + uses: chartboost/ruff-action@v1 - name: black run: | black --check . - - name: isort - run: | - isort --check --profile black . - name: mypy run: | mypy . - - name: pylint - run: | - pylint "${{ steps.common.outputs.MAIN_SRC_DIR }}" - - name: flake8 - run: | - flake8 --config .flake8 - - name: bandit - run: | - bandit -r "${{ steps.common.outputs.MAIN_SRC_DIR }}" - name: Check license header and file run: | ./scripts/license_checker.py diff --git a/.gitignore b/.gitignore index 28b8a9dc..a71cfd2a 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ +.ruff_cache/ prof/ # Translations diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 31f8a5b8..2cfb5dd4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,6 +7,19 @@ default_language_version: minimum_pre_commit_version: 3.0.0 repos: + - repo: local + hooks: + - id: update-hook-revs + name: "ensure hooks are up to date" + language: python + additional_dependencies: + - "typer" + fail_fast: true + always_run: true + entry: ./scripts/update_hook_revs.py + files: '\.pre-commit-config.yaml' + args: [--check] + pass_filenames: false - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: @@ -36,33 +49,17 @@ repos: - id: debug-statements - id: debug-statements - id: debug-statements + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.290 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.9.1 hooks: - id: black - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - args: [--profile, black] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.0.0 + rev: v1.5.1 hooks: - id: mypy args: [--no-warn-unused-ignores] - - repo: https://github.com/PyCQA/pylint - rev: v2.16.4 - hooks: - - id: pylint - args: [--disable=E0401] - exclude: tests|.devcontainer - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - args: [--config, .flake8] - - repo: https://github.com/PyCQA/bandit - rev: 1.7.4 - hooks: - - id: bandit - exclude: tests|.devcontainer|scripts diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index cfb50dbb..00000000 --- a/.pylintrc +++ /dev/null @@ -1,546 +0,0 @@ -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. -extension-pkg-allow-list= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. (This is an alternative name to extension-pkg-allow-list -# for backward compatibility.) -extension-pkg-whitelist=pydantic - -# Specify a score threshold to be exceeded before program exits with error. -fail-under=10.0 - -# Files or directories to be skipped. They should be base names, not paths. -ignore=CVS - - -# Files or directories matching the regex patterns are skipped. The regex -# matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the -# number of processors available to use. -jobs=1 - -# Control the amount of potential inferred values when inferring a single -# object. This can help the performance when dealing with large functions or -# complex, nested conditions. -limit-inference-results=100 - -# List of plugins (as comma separated values of python module names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages. -suggestion-mode=yes - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once). You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use "--disable=all --enable=classes -# --disable=W". -disable= - duplicate-code, # is behaving strangely sometimes and cannot - # be disabled on an individual basis: - # https://github.com/PyCQA/pylint/issues/214 - - too-few-public-methods, # says that classes should always have methods - # but that is not true anymore (e.g. dataclasses) - - unnecessary-ellipsis, # often used for interfaces/protocols - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable=c-extension-no-member - - -[REPORTS] - -# Python expression which should return a score less than or equal to 10. You -# have access to the variables 'error', 'warning', 'refactor', and 'convention' -# which contain the number of messages in each category, as well as 'statement' -# which is the total number of statements analyzed. This score is used by the -# global evaluation report (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details. -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio). You can also give a reporter class, e.g. -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages. -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=sys.exit,argparse.parse_error - - -[STRING] - -# This flag controls whether inconsistent-quotes generates a warning when the -# character used as a quote delimiter is used inconsistently within a module. -check-quote-consistency=no - -# This flag controls whether the implicit-str-concat should generate a warning -# on implicit string concatenation in sequences defined over several lines. -check-str-concat-over-line-jumps=no - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX, - TODO - -# Regular expression of note tags to take in consideration. -#notes-rgx= - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes. -max-spelling-suggestions=4 - -# Spelling dictionary name. Available dictionaries: none. To make it work, -# install the 'python-enchant' package. -spelling-dict= - -# List of comma separated words that should be considered directives if they -# appear and the beginning of a comment and should not be checked. -spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains the private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to the private dictionary (see the -# --spelling-private-dict-file option) instead of raising a message. -spelling-store-unknown-words=no - - -[BASIC] - -# Naming style matching correct argument names. -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style. -#argument-rgx= - -# Naming style matching correct attribute names. -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style. -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma. -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Bad variable names regexes, separated by a comma. If names match any regex, -# they will always be refused -bad-names-rgxs= - -# Naming style matching correct class attribute names. -class-attribute-naming-style=any - -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style. -#class-attribute-rgx= - -# Naming style matching correct class constant names. -class-const-naming-style=UPPER_CASE - -# Regular expression matching correct class constant names. Overrides class- -# const-naming-style. -#class-const-rgx= - -# Naming style matching correct class names. -class-naming-style=PascalCase - -# Regular expression matching correct class names. Overrides class-naming- -# style. -#class-rgx= - -# Naming style matching correct constant names. -const-naming-style=UPPER_CASE - -# Regular expression matching correct constant names. Overrides const-naming- -# style. -#const-rgx= - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names. -function-naming-style=snake_case - -# Regular expression matching correct function names. Overrides function- -# naming-style. -#function-rgx= - -# Good variable names which should always be accepted, separated by a comma. -good-names=i, - j, - k, - ex, - ok, - Run, - _, - __, - id, - db, - -# Good variable names regexes, separated by a comma. If names match any regex, -# they will always be accepted -good-names-rgxs= - -# Include a hint for the correct naming format with invalid-name. -include-naming-hint=no - -# Naming style matching correct inline iteration names. -inlinevar-naming-style=any - -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style. -#inlinevar-rgx= - -# Naming style matching correct method names. -method-naming-style=snake_case - -# Regular expression matching correct method names. Overrides method-naming- -# style. -#method-rgx= - -# Naming style matching correct module names. -module-naming-style=snake_case - -# Regular expression matching correct module names. Overrides module-naming- -# style. -#module-rgx= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -# These decorators are taken in consideration only for invalid-name. -property-classes=abc.abstractproperty - -# Naming style matching correct variable names. -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style. -#variable-rgx= - - -[LOGGING] - -# The type of string formatting that logging methods do. `old` means using % -# formatting, `new` is for `{}` formatting. -logging-format-style=old - -# Logging modules to check that the string format arguments are in logging -# function parameter format. -logging-modules=logging - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid defining new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of names allowed to shadow builtins -allowed-redefined-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expected to -# not be used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore. -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# Tells whether to warn about missing members when the owner of the attribute -# is inferred to be None. -ignore-none=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis). It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - -# List of decorators that change the signature of a decorated function. -signature-mutators= - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module. -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[DESIGN] - -# Maximum number of arguments for function / method. -max-args=5 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in an if statement (see R0916). -max-bool-expr=5 - -# Maximum number of branch for function / method body. -max-branches=12 - -# Maximum number of locals for function / method body. -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body. -max-returns=6 - -# Maximum number of statements in function / method body. -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[IMPORTS] - -# List of modules that can be imported at any level, not just the top level -# one. -allow-any-import-level= - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma. -deprecated-modules=optparse,tkinter.tix - -# Output a graph (.gv or any supported image format) of external dependencies -# to the given file (report RP0402 must not be disabled). -ext-import-graph= - -# Output a graph (.gv or any supported image format) of all (i.e. internal and -# external) dependencies to the given file (report RP0402 must not be -# disabled). -import-graph= - -# Output a graph (.gv or any supported image format) of internal dependencies -# to the given file (report RP0402 must not be disabled). -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Couples of modules and preferred modules, separated by a comma. -preferred-modules= - - -[CLASSES] - -# Warn about protected attribute access inside special methods -check-protected-access-in-special-methods=no - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp, - __post_init__ - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=cls - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "builtins.BaseException, builtins.Exception". -overgeneral-exceptions=builtins.BaseException, - builtins.Exception diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 00000000..a8538202 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,51 @@ +exclude = [ + ".git", + ".devcontainer", + "__pycache__", + "build", + "dist", +] + +ignore = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings - pycodestyle covered by black + "PLW", # pylint warnings + "RUF001", # ambiguous unicode character strings + "RUF010", # explicit conversion to string or repr: !s or !r + "B008", # function call in arg defaults +] + +line-length = 88 + +select = [ + "C90", # McCabe Complexity + "F", # pyflakes codes + "I", # isort + "S", # flake8-bandit + "B", # flake8-bugbear + "N", # pep8-naming + "UP", # pyupgrade + "PL", # pylint + "RUF", # ruff + "SIM", # flake8-simplify + "D", # pydocstyle +] + +fixable = [ + "UP", # e.g. List -> list + "I", # sort imports + "D", # pydocstyle +] + +target-version = "py39" + +[mccabe] +max-complexity = 10 + +[per-file-ignores] +"scripts/*" = ["PL", "S", "SIM", "D"] +"tests/*" = ["S", "SIM"] +".devcontainer/*" = ["S", "SIM", "D"] + +[pydocstyle] +convention = "pep257" diff --git a/.static_files b/.static_files index cc53aaa7..0290f0d9 100644 --- a/.static_files +++ b/.static_files @@ -23,6 +23,7 @@ scripts/update_config_docs.py scripts/update_template_files.py scripts/update_openapi_docs.py scripts/update_readme.py +scripts/update_lock.py scripts/README.md .github/workflows/check_config_docs.yaml @@ -36,12 +37,11 @@ scripts/README.md example_data/README.md .editorconfig -.flake8 .gitattributes .gitignore .pre-commit-config.yaml -.pylintrc .mypy.ini +.ruff.toml pytest.ini LICENSE diff --git a/openapi.yaml b/openapi.yaml index e75a7c6b..fbdfe9d1 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1,7 +1,7 @@ components: schemas: Greeting: - description: A container storing a greeting for a specfic person incl. metadata + description: A container storing a greeting for a specfic person incl. metadata. properties: created_at: description: The date/time when the message was created @@ -69,7 +69,7 @@ openapi: 3.0.2 paths: /: get: - description: Greet the World + description: Greet the World. operationId: index__get responses: '200': diff --git a/requirements-dev-common.in b/requirements-dev-common.in index ada5dbd7..1c677cd3 100644 --- a/requirements-dev-common.in +++ b/requirements-dev-common.in @@ -11,14 +11,10 @@ pre-commit>=3.1.1 mypy>=1.0.0 mypy-extensions>=1.0.0 -pylint>=2.16.4 -flake8>=6.0.0 -bandit>=1.7.4 +ruff>=0.0.290 black>=23.1.0 -isort>=5.12.0 - click>=8.1.0 typer>=0.7.0 diff --git a/requirements-dev.txt b/requirements-dev.txt index c0c3752a..fee0d6d0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.9 # by the following command: # -# pip-compile --generate-hashes --output-file=/workspace/requirements-dev.txt /tmp/tmpfjokrgaf/pyproject.toml /workspace/requirements-dev.in +# pip-compile --generate-hashes --output-file=/workspace/requirements-dev.txt /tmp/tmp1ommg4v0/pyproject.toml /workspace/requirements-dev.in # aiokafka==0.8.0 \ --hash=sha256:021e9f0027ca63c6c04daccfdd0e985f7a56d51bd0d43f482f674a58fada52f5 \ @@ -44,10 +44,6 @@ anyio==4.0.0 \ # httpcore # starlette # watchfiles -astroid==2.15.6 \ - --hash=sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c \ - --hash=sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd - # via pylint async-timeout==4.0.3 \ --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 @@ -58,10 +54,6 @@ attrs==23.1.0 \ # via # jsonschema # referencing -bandit==1.7.5 \ - --hash=sha256:75665181dc1e0096369112541a056c59d1c5f66f9bb74a8d686c3c362b83f549 \ - --hash=sha256:bdfc739baa03b880c2d15d0431b31c658ffc348e907fe197e54e0389dd59e11e - # via -r /workspace/requirements-dev-common.in black==23.9.1 \ --hash=sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f \ --hash=sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7 \ @@ -328,10 +320,6 @@ deprecation==2.1.0 \ --hash=sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff \ --hash=sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a # via testcontainers -dill==0.3.7 \ - --hash=sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e \ - --hash=sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03 - # via pylint distlib==0.3.7 \ --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \ --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8 @@ -365,26 +353,14 @@ filelock==3.12.4 \ --hash=sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4 \ --hash=sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd # via virtualenv -flake8==6.1.0 \ - --hash=sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23 \ - --hash=sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5 - # via -r /workspace/requirements-dev-common.in -ghga-event-schemas==0.13.4 \ - --hash=sha256:8bdc98ad0c7d2d7d82b1dd9490a933fcf9c25424fcd6d28d6728fc7f5979e553 \ - --hash=sha256:eee2495a8b857016c8e03faa0b739ae7e03125d5a608a5ec31987e24a3433443 +ghga-event-schemas==0.13.5 \ + --hash=sha256:1ce129c7c969fe2b263483d55c500a3d7f75b6c97e0acb6f49ddd84eca1e1974 \ + --hash=sha256:c5fb0abab7d06512b2470bb84247473528051d109200ba69a87b6701e3384d6c # via my-microservice (pyproject.toml) ghga-service-commons[api]==0.7.0 \ --hash=sha256:17d86341496898649741a2774d987c21620594ce3441cdaa785c99d8d7c14e3b \ --hash=sha256:cd552ecbe521fb80910ed06673f1bbeeecc1122e3ce6eb415280031eb77ca09f # via my-microservice (pyproject.toml) -gitdb==4.0.10 \ - --hash=sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a \ - --hash=sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7 - # via gitpython -gitpython==3.1.36 \ - --hash=sha256:4bb0c2a6995e85064140d31a33289aa5dce80133a23d36fcd372d716c54d3ebf \ - --hash=sha256:8d22b5cfefd17c79914226982bb7851d6ade47545b1735a9d010a2a4c26d8388 - # via bandit gprof2dot==2022.7.29 \ --hash=sha256:45b4d298bd36608fccf9511c3fd88a773f7a1abc04d6cd39445b11ba43133ec5 \ --hash=sha256:f165b3851d3c52ee4915eb1bd6cca571e5759823c2cd0f71a79bda93c2dc85d6 @@ -467,21 +443,15 @@ iniconfig==2.0.0 \ --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # via pytest -isort==5.12.0 \ - --hash=sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504 \ - --hash=sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6 - # via - # -r /workspace/requirements-dev-common.in - # pylint jmespath==1.0.1 \ --hash=sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 \ --hash=sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe # via # boto3 # botocore -jsonschema==4.19.0 \ - --hash=sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb \ - --hash=sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f +jsonschema==4.19.1 \ + --hash=sha256:cd5f1f9ed9444e554b38ba003af06c0a8c2868131e56bfbef0550fb450c0330e \ + --hash=sha256:ec84cc37cfa703ef7cd4928db24f9cb31428a5d0fa77747b8b51a847458e0bbf # via # ghga-event-schemas # hexkit @@ -499,58 +469,6 @@ kafka-python==2.0.2 \ # via # aiokafka # testcontainers -lazy-object-proxy==1.9.0 \ - --hash=sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382 \ - --hash=sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82 \ - --hash=sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9 \ - --hash=sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494 \ - --hash=sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46 \ - --hash=sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30 \ - --hash=sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63 \ - --hash=sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4 \ - --hash=sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae \ - --hash=sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be \ - --hash=sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701 \ - --hash=sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd \ - --hash=sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006 \ - --hash=sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a \ - --hash=sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586 \ - --hash=sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8 \ - --hash=sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821 \ - --hash=sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07 \ - --hash=sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b \ - --hash=sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171 \ - --hash=sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b \ - --hash=sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2 \ - --hash=sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7 \ - --hash=sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4 \ - --hash=sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8 \ - --hash=sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e \ - --hash=sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f \ - --hash=sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda \ - --hash=sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4 \ - --hash=sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e \ - --hash=sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671 \ - --hash=sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11 \ - --hash=sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455 \ - --hash=sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734 \ - --hash=sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb \ - --hash=sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59 - # via astroid -markdown-it-py==3.0.0 \ - --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ - --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb - # via rich -mccabe==0.7.0 \ - --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \ - --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e - # via - # flake8 - # pylint -mdurl==0.1.2 \ - --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ - --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba - # via markdown-it-py motor==3.1.1 \ --hash=sha256:01d93d7c512810dcd85f4d634a7244ba42ff6be7340c869791fe793561e734da \ --hash=sha256:a4bdadf8a08ebb186ba16e557ba432aa867f689a42b80f2e9f8b24bbb1604742 @@ -609,10 +527,6 @@ pathspec==0.11.2 \ --hash=sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20 \ --hash=sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3 # via black -pbr==5.11.1 \ - --hash=sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b \ - --hash=sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3 - # via stevedore pip-tools==7.3.0 \ --hash=sha256:8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e \ --hash=sha256:8e9c99127fe024c025b46a0b2d15c7bd47f18f33226cf7330d35493663fc1d1d @@ -622,7 +536,6 @@ platformdirs==3.10.0 \ --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d # via # black - # pylint # virtualenv pluggy==1.3.0 \ --hash=sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12 \ @@ -632,10 +545,6 @@ pre-commit==3.4.0 \ --hash=sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522 \ --hash=sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945 # via -r /workspace/requirements-dev-common.in -pycodestyle==2.11.0 \ - --hash=sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0 \ - --hash=sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8 - # via flake8 pydantic[email]==1.10.6 \ --hash=sha256:012c99a9c0d18cfde7469aa1ebff922e24b0c706d03ead96940f5465f2c9cf62 \ --hash=sha256:0abd9c60eee6201b853b6c4be104edfba4f8f6c5f3623f8e1dba90634d63eb35 \ @@ -678,18 +587,6 @@ pydantic[email]==1.10.6 \ # ghga-event-schemas # ghga-service-commons # hexkit -pyflakes==3.1.0 \ - --hash=sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774 \ - --hash=sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc - # via flake8 -pygments==2.16.1 \ - --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \ - --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29 - # via rich -pylint==2.17.5 \ - --hash=sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413 \ - --hash=sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252 - # via -r /workspace/requirements-dev-common.in pymongo==4.5.0 \ --hash=sha256:076afa0a4a96ca9f77fec0e4a0d241200b3b3a1766f8d7be9a905ecf59a7416b \ --hash=sha256:08819da7864f9b8d4a95729b2bea5fffed08b63d3b9c15b4fea47de655766cf5 \ @@ -854,7 +751,6 @@ pyyaml==6.0 \ --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \ --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5 # via - # bandit # hexkit # jsonschema2md # pre-commit @@ -875,10 +771,6 @@ rfc3986[idna2008]==1.5.0 \ --hash=sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835 \ --hash=sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97 # via httpx -rich==13.5.3 \ - --hash=sha256:87b43e0543149efa1253f485cd845bb7ee54df16c9617b8a893650ab84b4acb6 \ - --hash=sha256:9257b468badc3d347e146a4faa268ff229039d4c2d176ab0cffb4c4fbc73d5d9 - # via bandit rpds-py==0.10.3 \ --hash=sha256:015de2ce2af1586ff5dc873e804434185199a15f7d96920ce67e50604592cae9 \ --hash=sha256:061c3ff1f51ecec256e916cf71cc01f9975af8fb3af9b94d3c0cc8702cfea637 \ @@ -980,6 +872,25 @@ rpds-py==0.10.3 \ # via # jsonschema # referencing +ruff==0.0.290 \ + --hash=sha256:0e2b09ac4213b11a3520221083866a5816616f3ae9da123037b8ab275066fbac \ + --hash=sha256:150bf8050214cea5b990945b66433bf9a5e0cef395c9bc0f50569e7de7540c86 \ + --hash=sha256:1d9be6351b7889462912e0b8185a260c0219c35dfd920fb490c7f256f1d8313e \ + --hash=sha256:2ab41bc0ba359d3f715fc7b705bdeef19c0461351306b70a4e247f836b9350ed \ + --hash=sha256:35e3550d1d9f2157b0fcc77670f7bb59154f223bff281766e61bdd1dd854e0c5 \ + --hash=sha256:461fbd1fb9ca806d4e3d5c745a30e185f7cf3ca77293cdc17abb2f2a990ad3f7 \ + --hash=sha256:4ca6285aa77b3d966be32c9a3cd531655b3d4a0171e1f9bf26d66d0372186767 \ + --hash=sha256:75386ebc15fe5467248c039f5bf6a0cfe7bfc619ffbb8cd62406cd8811815fca \ + --hash=sha256:75cdc7fe32dcf33b7cec306707552dda54632ac29402775b9e212a3c16aad5e6 \ + --hash=sha256:949fecbc5467bb11b8db810a7fa53c7e02633856ee6bd1302b2f43adcd71b88d \ + --hash=sha256:982af5ec67cecd099e2ef5e238650407fb40d56304910102d054c109f390bf3c \ + --hash=sha256:ac93eadf07bc4ab4c48d8bb4e427bf0f58f3a9c578862eb85d99d704669f5da0 \ + --hash=sha256:ae5a92dfbdf1f0c689433c223f8dac0782c2b2584bd502dfdbc76475669f1ba1 \ + --hash=sha256:bbd37352cea4ee007c48a44c9bc45a21f7ba70a57edfe46842e346651e2b995a \ + --hash=sha256:d748c8bd97874f5751aed73e8dde379ce32d16338123d07c18b25c9a2796574a \ + --hash=sha256:eb07f37f7aecdbbc91d759c0c09870ce0fb3eed4025eebedf9c4b98c69abd527 \ + --hash=sha256:f1f49f5ec967fd5778813780b12a5650ab0ebcb9ddcca28d642c689b36920796 + # via -r /workspace/requirements-dev-common.in s3transfer==0.6.2 \ --hash=sha256:b014be3a8a2aab98cfe1abc7229cc5a9a0cf05eb9c1f2b86b230fd8df3f78084 \ --hash=sha256:cab66d3380cca3e70939ef2255d01cd8aece6a4907a9528740f668c4b0611861 @@ -991,10 +902,6 @@ six==1.16.0 \ # dependency-injector # pytest-profiling # python-dateutil -smmap==5.0.1 \ - --hash=sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62 \ - --hash=sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da - # via gitdb snakeviz==2.2.0 \ --hash=sha256:569e2d71c47f80a886aa6e70d6405cb6d30aa3520969ad956b06f824c5f02b8e \ --hash=sha256:7bfd00be7ae147eb4a170a471578e1cd3f41f803238958b6b8efcf2c698a6aa9 @@ -1010,10 +917,6 @@ starlette==0.27.0 \ --hash=sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75 \ --hash=sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91 # via fastapi -stevedore==5.1.0 \ - --hash=sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d \ - --hash=sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c - # via bandit stringcase==1.2.0 \ --hash=sha256:48a06980661908efe8d9d34eab2b6c13aefa2163b3ced26972902e3bdfd87008 # via -r /workspace/requirements-dev-common.in @@ -1030,17 +933,12 @@ tomli==2.0.1 \ # coverage # mypy # pip-tools - # pylint # pyproject-hooks # pytest tomli-w==1.0.0 \ --hash=sha256:9f2a07e8be30a0729e533ec968016807069991ae2fd921a78d42f429ae5f4463 \ --hash=sha256:f463434305e0336248cac9c2dc8076b707d8a12d019dd349f5c1e382dd1ae1b9 # via -r /workspace/requirements-dev-common.in -tomlkit==0.12.1 \ - --hash=sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86 \ - --hash=sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899 - # via pylint tornado==6.3.3 \ --hash=sha256:1bd19ca6c16882e4d37368e0152f99c099bad93e0950ce55e71daed74045908f \ --hash=sha256:22d3c2fa10b5793da13c807e6fc38ff49a4f6e1e3868b0a6f4164768bb8e20f5 \ @@ -1064,11 +962,9 @@ typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via - # astroid # black # mypy # pydantic - # pylint # starlette urllib3==1.26.16 \ --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f \ @@ -1298,9 +1194,7 @@ wrapt==1.15.0 \ --hash=sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09 \ --hash=sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559 \ --hash=sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639 - # via - # astroid - # testcontainers + # via testcontainers zipp==3.17.0 \ --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 diff --git a/requirements.txt b/requirements.txt index f42e24b9..3e061175 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.9 # by the following command: # -# pip-compile --generate-hashes --output-file=/workspace/requirements.txt /tmp/tmp1tc7_un5/pyproject.toml /workspace/requirements.in +# pip-compile --constraint=/workspace/requirements-dev.txt --generate-hashes --output-file=/workspace/requirements.txt /tmp/tmp1ommg4v0/pyproject.toml # aiokafka==0.8.0 \ --hash=sha256:021e9f0027ca63c6c04daccfdd0e985f7a56d51bd0d43f482f674a58fada52f5 \ @@ -188,9 +188,9 @@ fastapi==0.96.0 \ # via # -c /workspace/requirements-dev.txt # ghga-service-commons -ghga-event-schemas==0.13.4 \ - --hash=sha256:8bdc98ad0c7d2d7d82b1dd9490a933fcf9c25424fcd6d28d6728fc7f5979e553 \ - --hash=sha256:eee2495a8b857016c8e03faa0b739ae7e03125d5a608a5ec31987e24a3433443 +ghga-event-schemas==0.13.5 \ + --hash=sha256:1ce129c7c969fe2b263483d55c500a3d7f75b6c97e0acb6f49ddd84eca1e1974 \ + --hash=sha256:c5fb0abab7d06512b2470bb84247473528051d109200ba69a87b6701e3384d6c # via # -c /workspace/requirements-dev.txt # my-microservice (pyproject.toml) @@ -279,9 +279,9 @@ jmespath==1.0.1 \ # -c /workspace/requirements-dev.txt # boto3 # botocore -jsonschema==4.19.0 \ - --hash=sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb \ - --hash=sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f +jsonschema==4.19.1 \ + --hash=sha256:cd5f1f9ed9444e554b38ba003af06c0a8c2868131e56bfbef0550fb450c0330e \ + --hash=sha256:ec84cc37cfa703ef7cd4928db24f9cb31428a5d0fa77747b8b51a847458e0bbf # via # -c /workspace/requirements-dev.txt # ghga-event-schemas diff --git a/scripts/get_package_name.py b/scripts/get_package_name.py index bfd7835c..84d15fd9 100755 --- a/scripts/get_package_name.py +++ b/scripts/get_package_name.py @@ -27,7 +27,7 @@ def get_package_name() -> str: """Extracts the package name""" - with open(PYPROJECT_TOML_PATH, "r", encoding="utf8") as pyproject_toml: + with open(PYPROJECT_TOML_PATH, encoding="utf8") as pyproject_toml: for line in pyproject_toml.readlines(): line_stripped = line.strip() if line_stripped.startswith(NAME_PREFIX): diff --git a/scripts/license_checker.py b/scripts/license_checker.py index 2b4bdf98..52944330 100755 --- a/scripts/license_checker.py +++ b/scripts/license_checker.py @@ -26,7 +26,7 @@ import sys from datetime import date from pathlib import Path -from typing import List, Optional, Tuple, Union +from typing import Optional, Union # root directory of the package: ROOT_DIR = Path(__file__).parent.parent.resolve() @@ -53,6 +53,8 @@ ".flake8", ".gitignore", ".pylintrc", + ".ruff.toml", + ".ruff_cache", "example_config.yaml", "config_schema.json", "LICENSE", # is checked but not for the license header @@ -165,10 +167,10 @@ def __init__(self, file_path: Union[str, Path]): def get_target_files( target_dir: Path, - exclude: List[str] = EXCLUDE, - exclude_endings: List[str] = EXCLUDE_ENDINGS, - exclude_pattern: List[str] = EXCLUDE_PATTERN, -) -> List[Path]: + exclude: list[str] = EXCLUDE, + exclude_endings: list[str] = EXCLUDE_ENDINGS, + exclude_pattern: list[str] = EXCLUDE_PATTERN, +) -> list[Path]: """Get target files that are not match the exclude conditions. Args: target_dir (pathlib.Path): The target dir to search. @@ -202,7 +204,7 @@ def get_target_files( return target_files -def normalized_line(line: str, chars_to_trim: List[str] = COMMENT_CHARS) -> str: +def normalized_line(line: str, chars_to_trim: list[str] = COMMENT_CHARS) -> str: norm_line = line.strip() for char in chars_to_trim: @@ -211,11 +213,11 @@ def normalized_line(line: str, chars_to_trim: List[str] = COMMENT_CHARS) -> str: return norm_line.strip("\n").strip("\t").strip() -def normalized_text(text: str, chars_to_trim: List[str] = COMMENT_CHARS) -> str: +def normalized_text(text: str, chars_to_trim: list[str] = COMMENT_CHARS) -> str: "Normalize a license header text." lines = text.split("\n") - norm_lines: List[str] = [] + norm_lines: list[str] = [] for line in lines: stripped_line = line.strip() @@ -241,7 +243,7 @@ def format_copyright_template(copyright_template: str, author: str) -> str: return normalized_text(copyright_template.replace("{author}", author)) -def is_commented_line(line: str, comment_chars: List[str] = COMMENT_CHARS) -> bool: +def is_commented_line(line: str, comment_chars: list[str] = COMMENT_CHARS) -> bool: """Checks whether a line is a comment.""" line_stripped = line.strip() for comment_char in comment_chars: @@ -256,12 +258,12 @@ def is_empty_line(line: str) -> bool: return line.strip("\n").strip("\t").strip() == "" -def get_header(file_path: Path, comment_chars: List[str] = COMMENT_CHARS): +def get_header(file_path: Path, comment_chars: list[str] = COMMENT_CHARS): """Extracts the header from a file and normalizes it.""" - header_lines: List[str] = [] + header_lines: list[str] = [] try: - with open(file_path, "r") as file: + with open(file_path) as file: for line in file: if is_commented_line( line, comment_chars=comment_chars @@ -309,7 +311,7 @@ def check_copyright_notice( global_copyright: GlobalCopyrightNotice, copyright_template: str = COPYRIGHT_TEMPLATE, author: str = AUTHOR, - comment_chars: List[str] = COMMENT_CHARS, + comment_chars: list[str] = COMMENT_CHARS, min_year: int = MIN_YEAR, ) -> bool: """Checks the specified copyright text against a template. @@ -374,12 +376,12 @@ def check_file_headers( global_copyright: GlobalCopyrightNotice, copyright_template: str = COPYRIGHT_TEMPLATE, author: str = AUTHOR, - exclude: List[str] = EXCLUDE, - exclude_endings: List[str] = EXCLUDE_ENDINGS, - exclude_pattern: List[str] = EXCLUDE_PATTERN, - comment_chars: List[str] = COMMENT_CHARS, + exclude: list[str] = EXCLUDE, + exclude_endings: list[str] = EXCLUDE_ENDINGS, + exclude_pattern: list[str] = EXCLUDE_PATTERN, + comment_chars: list[str] = COMMENT_CHARS, min_year: int = MIN_YEAR, -) -> Tuple[List[Path], List[Path]]: +) -> tuple[list[Path], list[Path]]: """Check files for presence of a license header and verify that the copyright notice is up to date (correct year). @@ -416,8 +418,8 @@ def check_file_headers( ) # check if license header present in file: - passed_files: List[Path] = [] - failed_files: List[Path] = [] + passed_files: list[Path] = [] + failed_files: list[Path] = [] for target_file in target_files: try: @@ -445,7 +447,7 @@ def check_license_file( global_copyright: GlobalCopyrightNotice, copyright_template: str = COPYRIGHT_TEMPLATE, author: str = AUTHOR, - comment_chars: List[str] = COMMENT_CHARS, + comment_chars: list[str] = COMMENT_CHARS, min_year: int = MIN_YEAR, ) -> bool: """Currently only checks if the copyright notice in the @@ -472,7 +474,7 @@ def check_license_file( print(f'Could not find license file "{str(license_file)}".') return False - with open(license_file, "r") as file_: + with open(license_file) as file_: license_text = normalized_text(file_.read()) # Extract the copyright notice: @@ -524,7 +526,7 @@ def run(): global_copyright = GlobalCopyrightNotice() # get global copyright from .devcontainer/license_header.txt file: - with open(GLOBAL_COPYRIGHT_FILE_PATH, "r") as global_copyright_file: + with open(GLOBAL_COPYRIGHT_FILE_PATH) as global_copyright_file: global_copyright.text = normalized_text(global_copyright_file.read()) if args.no_license_file_check: diff --git a/scripts/update_config_docs.py b/scripts/update_config_docs.py index c5457ad0..ee77c567 100755 --- a/scripts/update_config_docs.py +++ b/scripts/update_config_docs.py @@ -25,7 +25,7 @@ import sys from difflib import unified_diff from pathlib import Path -from typing import Any, Type +from typing import Any import yaml from pydantic import BaseSettings @@ -43,7 +43,7 @@ class ValidationError(RuntimeError): """Raised when validation of config documentation fails.""" -def get_config_class() -> Type[BaseSettings]: +def get_config_class() -> type[BaseSettings]: """ Dynamically imports and returns the Config class from the current service. This makes the script service repo agnostic. @@ -121,7 +121,7 @@ def check_docs(): """ example_expected = get_example() - with open(EXAMPLE_CONFIG_YAML, "r", encoding="utf-8") as example_file: + with open(EXAMPLE_CONFIG_YAML, encoding="utf-8") as example_file: example_observed = example_file.read() if example_expected != example_observed: print_diff(example_expected, example_observed) @@ -130,7 +130,7 @@ def check_docs(): ) schema_expected = get_schema() - with open(CONFIG_SCHEMA_JSON, "r", encoding="utf-8") as schema_file: + with open(CONFIG_SCHEMA_JSON, encoding="utf-8") as schema_file: schema_observed = schema_file.read() if schema_expected != schema_observed: raise ValidationError( diff --git a/scripts/update_hook_revs.py b/scripts/update_hook_revs.py new file mode 100755 index 00000000..931d0ce5 --- /dev/null +++ b/scripts/update_hook_revs.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 + +# Copyright 2021 - 2023 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln +# for the German Human Genome-Phenome Archive (GHGA) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""Script to ensure the pre-commit hook revs match what is installed.""" +import re +import sys +from functools import partial +from pathlib import Path + +from script_utils import cli + +REPO_ROOT_DIR = Path(__file__).parent.parent.resolve() +PRE_COMMIT_CFG_PATH = REPO_ROOT_DIR / ".pre-commit-config.yaml" +LOCK_FILE_PATH = REPO_ROOT_DIR / "requirements-dev.txt" + + +def inspect_lock() -> dict[str, str]: + """Inspect the lock file to get the resolved dependencies""" + dependency_pattern = re.compile(r"([^=\s]+)==([^\s]*?)\s") + dependencies = {} + + # Get the set of dependencies from the requirements-dev.txt lock file + with open(LOCK_FILE_PATH, encoding="utf-8") as lock_file: + lines = lock_file.readlines() + + for line in lines: + match = re.match(dependency_pattern, line) + if match: + package, version = match.groups() + dependencies[package] = version + + return dependencies + + +def get_repl_value(match, dependencies: dict[str, str], outdated_hooks: list[str]): + """Look up pre-commit hook id in list of dependencies. If there's a match, update + `outdated_hooks` and return the hook version stored in the dictionary""" + ver, name = match.groups() + if name in dependencies: + new_ver = dependencies[name].strip() + + # Use the v prefix if it was used before + if ver.startswith("v"): + new_ver = ver[0] + new_ver + + # Make a list of what's outdated + if new_ver != ver: + msg = f"\t{name} (configured: {ver}, expected: {new_ver})" + outdated_hooks.append(msg) + return new_ver + return ver + + +def get_config(): + """Obtain the current pre-commit hook config from .pre-commit-config.yaml""" + with open(PRE_COMMIT_CFG_PATH, encoding="utf-8") as pre_commit_config: + return pre_commit_config.read() + + +def process_config(dependencies: dict[str, str], config: str) -> tuple[str, list[str]]: + """Compare pre-commit config with lock file dependencies. + + Create a modified copy of the existing config file contents with the hook versions + synchronized to the lock file dependencies. + + Returns: + `new_config`: the updated/synchronized pre-commit config. + + `outdated_hooks`: a list of any outdated hooks with version discrepancy details. + """ + outdated_hooks: list[str] = [] + + hook_rev = re.compile(r"([^\s\n]+)(?=\s*hooks:\s*- id: ([^\s]+))") + + new_config = re.sub( + hook_rev, + repl=partial( + get_repl_value, dependencies=dependencies, outdated_hooks=outdated_hooks + ), + string=config, + ) + + return new_config, outdated_hooks + + +def update_config(new_config: str): + """Write `new_config` to .pre-commit-config.yaml""" + with open(PRE_COMMIT_CFG_PATH, "w", encoding="utf-8") as pre_commit_config: + pre_commit_config.write(new_config) + cli.echo_success(f"Updated '{PRE_COMMIT_CFG_PATH}'") + + +def output_failure(outdated_hooks: list[str]): + """Notify the user that some pre-commit hooks are outdated, and list those hooks.""" + cli.echo_failure("The following pre-commit hook versions are outdated:") + for hook in outdated_hooks: + print(hook) + print("Run 'scripts/update_hook_revs.py' to update") + sys.exit(1) + + +def main(check: bool = False): + """Compare configured pre-commit hooks with the installed dependencies. + + For the set that overlap (e.g. `black`, `mypy`, `ruff`, etc.), make sure the + versions match. If running with `--check`, exit with status code 1 if anything is + outdated. If running without `--check`, update `.pre-commit-config.yaml` as needed. + """ + + dependencies = inspect_lock() + config = get_config() + new_config, outdated_hooks = process_config(dependencies, config) + + if config != new_config: + if check: + output_failure(outdated_hooks) + else: + update_config(new_config) + else: + cli.echo_success("Pre-commit hooks are up to date.") + + +if __name__ == "__main__": + cli.run(main) diff --git a/scripts/update_lock.py b/scripts/update_lock.py index fd57d01a..8dd78d0d 100755 --- a/scripts/update_lock.py +++ b/scripts/update_lock.py @@ -27,6 +27,7 @@ from pathlib import Path from tempfile import TemporaryDirectory +import stringcase import tomli import tomli_w from script_utils import cli @@ -60,7 +61,7 @@ def remove_self_dependencies(pyproject: dict) -> dict: project_metadata = modified_pyproject["project"] - package_name = project_metadata.get("name") + package_name = stringcase.spinalcase(project_metadata.get("name")) if not package_name: raise ValueError("The provided project metadata does not contain a name.") @@ -89,7 +90,7 @@ def fix_temp_dir_comments(file_path: Path): the requirements are indeed being generated if nothing else changes. """ - with open(file_path, "r", encoding="utf-8") as file: + with open(file_path, encoding="utf-8") as file: lines = file.readlines() with open(file_path, "w", encoding="utf-8") as file: @@ -109,8 +110,8 @@ def is_file_outdated(old_file: Path, new_file: Path) -> bool: header_comment = "# pip-compile" outdated = False - with open(old_file, "r", encoding="utf-8") as old: - with open(new_file, "r", encoding="utf-8") as new: + with open(old_file, encoding="utf-8") as old: + with open(new_file, encoding="utf-8") as new: old_lines = old.readlines() new_lines = new.readlines() if len(old_lines) != len(new_lines): diff --git a/scripts/update_openapi_docs.py b/scripts/update_openapi_docs.py index 456f514b..e2b2c643 100755 --- a/scripts/update_openapi_docs.py +++ b/scripts/update_openapi_docs.py @@ -72,7 +72,7 @@ def check_docs(): """ openapi_expected = get_openapi_spec() - with open(OPENAPI_YAML, "r", encoding="utf-8") as openapi_file: + with open(OPENAPI_YAML, encoding="utf-8") as openapi_file: openapi_observed = openapi_file.read() if openapi_expected != openapi_observed: diff --git a/scripts/update_readme.py b/scripts/update_readme.py index 0730a22a..87ada44e 100755 --- a/scripts/update_readme.py +++ b/scripts/update_readme.py @@ -142,7 +142,7 @@ def generate_config_docs() -> str: examples_as_yaml=False, show_examples="all", ) - with open(CONFIG_SCHEMA_PATH, "r", encoding="utf-8") as json_file: + with open(CONFIG_SCHEMA_PATH, encoding="utf-8") as json_file: config_schema = json.load(json_file) md_lines = parser.parse_schema(config_schema) diff --git a/scripts/update_template_files.py b/scripts/update_template_files.py index 952fe2c3..d3313fd5 100755 --- a/scripts/update_template_files.py +++ b/scripts/update_template_files.py @@ -58,7 +58,7 @@ class ValidationError(RuntimeError): def get_file_list(list_name: str) -> list[str]: """Return a list of all file names specified in a given list file.""" list_path = REPO_ROOT_DIR / list_name - with open(list_path, "r", encoding="utf8") as list_file: + with open(list_path, encoding="utf8") as list_file: file_list = [ clean_line for clean_line in ( @@ -127,7 +127,7 @@ def check_file(relative_file_path: str, diff: bool = False) -> bool: print(f" - {local_file_path}: cannot check, remote is missing") return True - with open(local_file_path, "r", encoding="utf8") as file: + with open(local_file_path, encoding="utf8") as file: return diff_content(local_file_path, file.read(), template_file_content) return False @@ -153,7 +153,7 @@ def update_file(relative_file_path: str, diff: bool = False) -> bool: return True if diff and local_file_path.exists(): - with open(local_file_path, "r", encoding="utf8") as file: + with open(local_file_path, encoding="utf8") as file: if file.read() == template_file_content: return False diff --git a/src/my_microservice/__init__.py b/src/my_microservice/__init__.py index c5d79541..bb514949 100644 --- a/src/my_microservice/__init__.py +++ b/src/my_microservice/__init__.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Short description of package""" # Please adapt to package +"""Short description of package.""" # Please adapt to package from importlib.metadata import version diff --git a/src/my_microservice/__main__.py b/src/my_microservice/__main__.py index 0b4684c7..303774aa 100644 --- a/src/my_microservice/__main__.py +++ b/src/my_microservice/__main__.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Entrypoint of the package""" +"""Entrypoint of the package.""" import asyncio @@ -24,7 +24,7 @@ def run(config: Config = CONFIG): - """Run the service""" + """Run the service.""" # Please adapt to package name asyncio.run(run_server(app="my_microservice.__main__:app", config=config)) diff --git a/src/my_microservice/api/__init__.py b/src/my_microservice/api/__init__.py index 8e6b03ec..ca43f808 100644 --- a/src/my_microservice/api/__init__.py +++ b/src/my_microservice/api/__init__.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Subpackage defining a RESTful API""" +"""Subpackage defining a RESTful API.""" diff --git a/src/my_microservice/api/deps.py b/src/my_microservice/api/deps.py index 6b164a1f..c5e321bc 100644 --- a/src/my_microservice/api/deps.py +++ b/src/my_microservice/api/deps.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""FastAPI dependencies (used with the `Depends` feature)""" +"""FastAPI dependencies (used with the `Depends` feature).""" from ..config import CONFIG diff --git a/src/my_microservice/api/main.py b/src/my_microservice/api/main.py index 5741d6ed..392baec8 100644 --- a/src/my_microservice/api/main.py +++ b/src/my_microservice/api/main.py @@ -15,6 +15,7 @@ """ Module containing the main FastAPI router and (optionally) top-level API enpoints. + Additional endpoints might be structured in dedicated modules (each of them having a sub-router). """ @@ -33,7 +34,7 @@ @app.get("/", summary="Greet the world") async def index(): - """Greet the World""" + """Greet the World.""" return "Hello World." @@ -47,5 +48,5 @@ async def index(): response_model=Greeting, ) async def greet(name: str, isinformal: bool = True, config=Depends(get_config)): - """Greet a person""" + """Greet a person.""" return generate_greeting(name=name, language=config.language, isinformal=isinformal) diff --git a/src/my_microservice/config.py b/src/my_microservice/config.py index d894389b..78311072 100644 --- a/src/my_microservice/config.py +++ b/src/my_microservice/config.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Config Parameter Modeling and Parsing""" +"""Config Parameter Modeling and Parsing.""" from ghga_service_commons.api import ApiConfigBase from hexkit.config import config_from_yaml diff --git a/src/my_microservice/core/__init__.py b/src/my_microservice/core/__init__.py index a327b2eb..c9f731b4 100644 --- a/src/my_microservice/core/__init__.py +++ b/src/my_microservice/core/__init__.py @@ -15,5 +15,6 @@ """ This sub-package contains the main business functionality of this service. + It should not contain any service API-related code. """ diff --git a/src/my_microservice/core/greeting.py b/src/my_microservice/core/greeting.py index 2dad5a34..4a56f903 100644 --- a/src/my_microservice/core/greeting.py +++ b/src/my_microservice/core/greeting.py @@ -36,7 +36,6 @@ def generate_greeting(name: str, language: str, isinformal: bool): """Generate a greeting for a specific person.""" - # search for suitable expressions (might be multiple): expression_hits = [ expr @@ -52,7 +51,7 @@ def generate_greeting(name: str, language: str, isinformal: bool): ) # pick a random expression from the list of hits: - expression = random.choice(expression_hits) # nosec + expression = random.choice(expression_hits) # nosec # noqa: S311 # assemble the greeting phrase: greeting_phrase = f"{expression.expression} {name}!" diff --git a/src/my_microservice/models.py b/src/my_microservice/models.py index 0bac679e..6a5c6db3 100644 --- a/src/my_microservice/models.py +++ b/src/my_microservice/models.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Defines dataclasses for holding business-logic data""" +"""Defines dataclasses for holding business-logic data.""" from datetime import datetime @@ -28,7 +28,7 @@ class MessageBase(BaseModel): - """A message base container""" + """A message base container.""" message: str = Field(..., description="The message content.") created_at: datetime = Field( @@ -37,7 +37,7 @@ class MessageBase(BaseModel): class GreetingBase(BaseModel): - """A container for basic metadata on a greeting phrase/expression""" + """A container for basic metadata on a greeting phrase/expression.""" language: SupportedLanguages = Field(..., description="The language.") isinformal: bool = Field( @@ -46,12 +46,12 @@ class GreetingBase(BaseModel): class GreetingExpression(GreetingBase): - """A container for describing a greeting expression""" + """A container for describing a greeting expression.""" expression: str = Field(..., description="The actual greeting expression") class Greeting(GreetingBase, MessageBase): - """A container storing a greeting for a specfic person incl. metadata""" + """A container storing a greeting for a specfic person incl. metadata.""" pass # pylint: disable=unnecessary-pass diff --git a/tests/__init__.py b/tests/__init__.py index 6f368976..43aaf730 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Package containing both unit and integration tests""" +"""Package containing both unit and integration tests.""" diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py index b8a4adb5..78f4baa0 100644 --- a/tests/fixtures/__init__.py +++ b/tests/fixtures/__init__.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Fixtures that are used in both integration and unit tests""" +"""Fixtures that are used in both integration and unit tests.""" diff --git a/tests/fixtures/utils.py b/tests/fixtures/utils.py index cbed094e..92c10e8f 100644 --- a/tests/fixtures/utils.py +++ b/tests/fixtures/utils.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Utils for Fixture handling""" +"""Utils for Fixture handling.""" from pathlib import Path