From 6fac5d0ce8187ca250b534eac6c8245b97bb8e6c Mon Sep 17 00:00:00 2001 From: Bracey Summers Date: Fri, 21 Feb 2025 19:32:29 -0600 Subject: [PATCH] - APP-4733 - [PACKAGE] Migrated to "uv" for package management - APP-4734 - [PACKAGE] Switched linters to "ruff" (including linting fixes) --- .pre-commit-config.yaml | 42 ++++------ auth/hmac_auth.py | 2 +- auth/tc_auth.py | 5 +- pyproject.toml | 165 ++++++++++++++++++++++++++++++++-------- requests_tc.py | 2 +- tc_session.py | 34 +++++---- 6 files changed, 169 insertions(+), 81 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a0cdb75..aeba711 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,10 +34,6 @@ repos: (?x)( ^tests/ ) - - repo: https://github.com/psf/black - rev: 24.10.0 - hooks: - - id: black - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: @@ -50,40 +46,30 @@ repos: (?x)( ^app_init/ ) - - repo: https://github.com/pycqa/pydocstyle - rev: 6.3.0 - hooks: - - id: pydocstyle - args: - - --ignore=D104,D202,D203,D213,D300,D301,D400,D402,D406,D407,D413,D415 - exclude: | - (?x)( - ^tcex/threat_intelligence/| - ^tests/ - ) - repo: https://github.com/asottile/pyupgrade rev: v3.19.0 hooks: - id: pyupgrade args: - --py311-plus - - repo: https://github.com/yunojuno/pre-commit-xenon - rev: v0.1 - hooks: - - id: xenon - args: ['--max-average=B', '-e=tests*'] - repo: local hooks: - id: pyright entry: pyright language: system name: pyright - types: [python] - - repo: local + types: + - python + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.9.7 hooks: - - id: pylint - entry: pylint - language: system - name: pylint - types: [python] - args: ['--jobs=2'] + - id: ruff + args: + - --fix + types_or: + - python + - pyi + - id: ruff-format + types_or: + - python + - pyi diff --git a/auth/hmac_auth.py b/auth/hmac_auth.py index 316ddf7..7f5e09b 100644 --- a/auth/hmac_auth.py +++ b/auth/hmac_auth.py @@ -9,7 +9,7 @@ # third-party from requests import PreparedRequest, auth -from ...input.field_type.sensitive import Sensitive # type: ignore # pylint: disable=import-error +from ...input.field_type.sensitive import Sensitive # type: ignore class HmacAuth(auth.AuthBase): diff --git a/auth/tc_auth.py b/auth/tc_auth.py index ad88145..cc4eaea 100644 --- a/auth/tc_auth.py +++ b/auth/tc_auth.py @@ -4,7 +4,7 @@ import time from collections.abc import Callable -from ...input.field_type.sensitive import Sensitive # type: ignore # pylint: disable=import-error +from ...input.field_type.sensitive import Sensitive # type: ignore from .hmac_auth import HmacAuth from .token_auth import TokenAuth @@ -26,7 +26,8 @@ def __init__( TokenAuth.__init__(self, tc_token) self.auth_type = 'token' else: # pragma: no cover - raise RuntimeError('No valid ThreatConnect API credentials provided.') + ex_msg = 'No valid ThreatConnect API credentials provided.' + raise RuntimeError(ex_msg) def __call__(self, r): # type: ignore """Add the authorization headers to the request.""" diff --git a/pyproject.toml b/pyproject.toml index 45193cc..bafa13b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,8 @@ -[tool.black] -line-length = 100 -skip-string-normalization = true - [tool.codespell] +# https://streetsidesoftware.com/vscode-spell-checker/ + # ignore-words-list= -skip = "*.history,*local" +skip = "*.cspell*,*.history,*local,uv.lock" [tool.isort] dedup_headings = false @@ -18,42 +16,21 @@ known_third_party = "" line_length = 100 profile = "black" -[tool.pydocstyle] -ignore = [ - "D202", # no blank lines allowed after function docstring - "D203", # 1 blank line required before class docstring (found 0) - "D213", # Multi-line docstring summary should start at the second line - "D400", # First line should end with a period ... - "D406", # Section name should end with a newline ... - "D407", # Missing dashed underline after section ... - "D413", # Missing blank line after last section ... - "D415", # First line should end with a period, question mark, or exclamation point ... -] - -[tool.pylint.messages_control] -disable = [ - "broad-exception-caught", - "fixme", - "invalid-name", - "logging-fstring-interpolation", - "relative-beyond-top-level", # disable relative rule due to this project being a submodule - "too-few-public-methods", - "too-many-arguments", - "too-many-branches", - "too-many-instance-attributes", - "too-many-positional-arguments", - "too-many-public-methods", -] -extension-pkg-whitelist = "pydantic" - [tool.pyright] # https://github.com/microsoft/pyright/blob/main/docs/configuration.md#sample-pyprojecttoml-file + exclude = [ "**/.history", "**/__pycache__", + "**/local-*", + "tcex/api/tc/v2", + "tests", ] pythonPlatform = "Linux" pythonVersion = "3.11" +reportIncompatibleMethodOverride = false +reportIncompatibleVariableOverride = false +reportPrivateImportUsage = false [tool.pytest.ini_options] filterwarnings = [] @@ -61,3 +38,125 @@ junit_family = "xunit2" testpaths = [ "tests", ] + +[tool.ruff] +# https://docs.astral.sh/ruff/ + +# exclude additional directories, outside of .gitignore. +exclude = [ + "tests", +] + +# set line length to match black +line-length = 100 + +# set the python target +target-version = "py311" + +[tool.ruff.format] +# https://docs.astral.sh/ruff/formatter/ + +docstring-code-format = true +docstring-code-line-length = 60 +indent-style = "space" +line-ending = "auto" +quote-style = "single" +skip-magic-trailing-comma = false + +[tool.ruff.lint] +# https://docs.astral.sh/ruff/linter/ + +# control "--fix" behavior. +# fixable = [] +# unfixable = [] + +# https://beta.ruff.rs/docs/configuration/#error-suppression +ignore = [ + "B008", # Do not perform function call ... in argument defaults; instead, perform ... + "B011", # do not call assert False since python -O removes these calls + "BLE001", # Do not catch blind exception: ... + "C901", # ... is too complex + "D202", # no blank lines allowed after function docstring + "D203", # 1 blank line required before class docstring (found 0) + "D213", # Multi-line docstring summary should start at the second line + "D400", # First line should end with a period ... + "D406", # Section name should end with a newline ... + "D407", # Missing dashed underline after section ... + "D413", # Missing blank line after last section ... + "D415", # First line should end with a period, question mark, or exclamation point ... + "E402", # module level import not at top of file + "FBT001", # Boolean-typed positional argument in function definition + "FBT002", # Boolean default positional argument in function definition + "G004", # Logging statement uses f-string + "N818", # Exception name ... should be named with an Error suffix + "PGH003", # Use specific rule codes when ignoring type issues + "PLR0912", # Too many branches + "PLR0913", # Too many arguments in function definition + "PT006", # Wrong name(s) type in ..., expected ... + "TC001", # Move application import ... into a type-checking block + "TID252", # Prefer absolute imports over relative imports from parent modules +] + +# control enabled plugins +select = [ + "A", # flake8-builtins + "ARG", # flake8-unused-arguments + "B", # flake8-bugbear + "BLE", # flake8-blind-except + "C", # flake8-comprehensions + "C4", # flake8-comprehensions + "C90", # mccabe + "D", # pydocstyle + "DJ", # flake8-django + "DTZ", # flake8-datetimez + "E", # pycodestyle + "W", # pycodestyle + "E", # pycodestyle + "EM", # flake8-errmsg + "EXE", # flake8-executable + "F", # Pyflakes + "FBT", # flake8-boolean-trap + "G", # flake8-logging-format + "I", # isort + "ICN", # flake8-import-conventions + "INP", # flake8-no-pep420 + "ISC", # flake8-implicit-str-concat + "N", # pep8-naming + "NPY", # NumPy-specific + "PD", # pandas-vet + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # Pylint + "PLC", # Convention + "PLE", # Error + "PLR", # Refactor + "PLW", # Warning + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "PYI", # flake8-pyi + "RET", # flake8-return + "RSE", # flake8-raise + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "SLF", # flake8-self + "T10", # flake8-debugger + "T20", # flake8-print + "TCH", # flake8-type-checking + "TID", # flake8-tidy-imports + "TRY", # tryceratops + "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020 +] + +# Other Options +# "ANN", # flake8-annotations +# "COM", # flake8-commas +# "ERA", # eradicate +# "S", # flake8-bandit +# "Q", # flake8-quotes + +[tool.ruff.lint.pydocstyle] +# https://docs.astral.sh/ruff/linter/ + +convention = "google" diff --git a/requests_tc.py b/requests_tc.py index ae58043..f4bb2a1 100644 --- a/requests_tc.py +++ b/requests_tc.py @@ -34,7 +34,7 @@ def get_session( auth: HmacAuth | TokenAuth | TcAuth | None = None, base_url: str | None = None, log_curl: bool | None = None, - proxies: dict[str, str] | None = None, # pylint: disable=redefined-outer-name + proxies: dict[str, str] | None = None, proxies_enabled: bool | None = None, verify: bool | str | None = None, ) -> TcSession: diff --git a/tc_session.py b/tc_session.py index eb62752..74f6e51 100644 --- a/tc_session.py +++ b/tc_session.py @@ -1,16 +1,16 @@ """TcEx Framework Module""" # standard library +import contextlib import logging # third-party import urllib3 -from requests import Response # TYPE-CHECKING -from requests import Session, adapters +from requests import Response, Session, adapters from urllib3.util.retry import Retry -from ..util.requests_to_curl import RequestsToCurl # type: ignore # pylint: disable=import-error -from ..util.util import Util # type: ignore # pylint: disable=import-error +from ..util.requests_to_curl import RequestsToCurl # type: ignore +from ..util.util import Util # type: ignore from .auth.hmac_auth import HmacAuth from .auth.tc_auth import TcAuth from .auth.token_auth import TokenAuth @@ -66,24 +66,26 @@ def _log_curl(self, response: Response): """Log the curl equivalent command.""" # don't show curl message for logging commands - if response.request.url is not None and '/v2/logs/app' not in response.request.url: - # APP-79 - adding logging of request as curl commands - if not response.ok or self.log_curl: - try: - self.log.debug( - self.requests_to_curl.convert( - response.request, proxies=self.proxies, verify=self.verify - ) + # APP-79 - adding logging of request as curl commands + # if response.request.url is not None and '/v2/logs/app' not in response.request.url: + # if not response.ok or self.log_curl: + if (response.request.url is not None and '/v2/logs/app' not in response.request.url) and ( + not response.ok or self.log_curl + ): + with contextlib.suppress(Exception): + self.log.debug( + self.requests_to_curl.convert( + response.request, proxies=self.proxies, verify=self.verify ) - except Exception: # nosec - pass # logging curl command is best effort + ) - def request(self, method, url, **kwargs): # pylint: disable=arguments-differ # type: ignore + def request(self, method, url, **kwargs): # type: ignore """Override request method disabling verify on token renewal if disabled on session.""" response = super().request(method, self.url(url), **kwargs) + bad_request_code = 401 # retry request in case we encountered a race condition with token renewal monitor - if response.status_code == 401: + if response.status_code == bad_request_code: self.log.debug( f'Unexpected response received while attempting to send a request using internal ' f'session object. Retrying request. feature=tc-session, '