Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .mise/scripts/generate_attributions.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def main() -> None:
if package_name:
cmd += ["--ignore-packages", package_name]

result = subprocess.run(cmd, capture_output=True, text=True, check=False) # noqa: S603
result = subprocess.run(cmd, capture_output=True, text=True, check=False) # ruff: ignore[subprocess-without-shell-equals-true]
if result.returncode != 0:
print(result.stderr, file=sys.stderr)
sys.exit(result.returncode)
Expand Down
78 changes: 39 additions & 39 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,52 +142,52 @@ line-length = 120
select = ["ALL"]

ignore = [
"ANN002", # missing type annotation for `*args` -> provides no value
"ANN003", # missing type annotation for `**kwargs`` -> provides no value
"ASYNC109", # async function definition with a `timeout` parameter -> as mentioned by ruff, "This rule is highly opinionated and may not be suitable for all use cases."
"CPY001", # missing copyright notice -> not for OSS
"DOC502", # docstrings with exceptions not raised in the code of the function -> not always necessary
"D203", # incomptatible with D211 -> prefer D211
"D212", # incompatible with D213 -> prefer D213
"FBT001", # boolean positional arguments -> disagree
"FBT002", # boolean defautl value positionl arguments -> disagree
"FBT003", # boolean positional value in function call -> disagree
"PGH003", # use specific rule codes when ignoring type issues -> quite a hassle, no value
"TRY300", # else instead of return before except. -> strongly disagree, hinders readabilty.
"COM812", # conflicts with ruff formatter -> not feasible nor recommended
"ISC001", # conflicts with ruff formatter -> not feasible nor recommended
"S404", # subprocess` module is possibly insecure -> as mentioned by ruff, unstable and preview
"FIX002", # line contains todo -> yes, that's what todo's are for?!
"TD003", # missing issue link for todo -> not in OSS
"PTH123", # use of open to be replaced with Path.open
"T201", # Remove `print`
"INP001", # Checks for packages that are missing an __init__.py file.
"RUF067", # __init__ module contains conditional imports -> needed for optional dependencies (preview rule)
"missing-type-args", # missing type annotation for `*args` -> provides no value
"missing-type-kwargs", # missing type annotation for `**kwargs`` -> provides no value
"async-function-with-timeout", # async function definition with a `timeout` parameter -> as mentioned by ruff, "This rule is highly opinionated and may not be suitable for all use cases."
"missing-copyright-notice", # missing copyright notice -> not for OSS
"docstring-extraneous-exception", # docstrings with exceptions not raised in the code of the function -> not always necessary
"incorrect-blank-line-before-class", # incomptatible with D211 -> prefer D211
"multi-line-summary-first-line", # incompatible with D213 -> prefer D213
"boolean-type-hint-positional-argument", # boolean positional arguments -> disagree
"boolean-default-value-positional-argument", # boolean defautl value positionl arguments -> disagree
"boolean-positional-value-in-call", # boolean positional value in function call -> disagree
"blanket-type-ignore", # use specific rule codes when ignoring type issues -> quite a hassle, no value
"try-consider-else", # else instead of return before except. -> strongly disagree, hinders readabilty.
"missing-trailing-comma", # conflicts with ruff formatter -> not feasible nor recommended
"single-line-implicit-string-concatenation", # conflicts with ruff formatter -> not feasible nor recommended
"suspicious-subprocess-import", # subprocess` module is possibly insecure -> as mentioned by ruff, unstable and preview
"line-contains-todo", # line contains todo -> yes, that's what todo's are for?!
"missing-todo-link", # missing issue link for todo -> not in OSS
"builtin-open", # use of open to be replaced with Path.open
"print", # Remove `print`
"implicit-namespace-package", # Checks for packages that are missing an __init__.py file.
"non-empty-init-module", # __init__ module contains conditional imports -> needed for optional dependencies (preview rule)
]

[tool.ruff.lint.per-file-ignores]
"**/tests/**/*.py" = [
# we are more relaxed in tests, while sill applying hundreds of rules
"S101", # asserts allowed in tests...
"assert", # asserts allowed in tests...
"ARG", # unused function args -> fixtures nevertheless are functionally relevant...
"FBT", # don't care about booleans as positional arguments in tests, e.g. via @pytest.mark.parametrize()
"PLR2004", # magic value used in comparison, ...
"PLR6301", # method could be a function, class method, or static method -> test organization pattern
"PT011", # exception to broad
"PLC2701", # private import, but required for unit testing
"PLC0415", # local import
"PT012", # exception to broad
"S311", # standard pseudo-random generators are not suitable for cryptographic purposes
"SLF001", # private member access required for unit testing
"S603", # check for execution of untrusted input
"ANN001", # missing type annotation for function argument
"ANN002", # missing type annotation
"ANN003", # missing type annotation
"ANN202", # missing return type annotation
"DOC201", # `return` is not documented in docstring
"ASYNC230", # async functions should not open files with blocking methods like `open`
"S104", # bind to all ports
"S607", # subprocess with partial path
"magic-value-comparison", # magic value used in comparison, ...
"no-self-use", # method could be a function, class method, or static method -> test organization pattern
"pytest-raises-too-broad", # exception to broad
"import-private-name", # private import, but required for unit testing
"import-outside-top-level", # local import
"pytest-raises-with-multiple-statements", # exception to broad
"suspicious-non-cryptographic-random-usage", # standard pseudo-random generators are not suitable for cryptographic purposes
"private-member-access", # private member access required for unit testing
"subprocess-without-shell-equals-true", # check for execution of untrusted input
"missing-type-function-argument", # missing type annotation for function argument
"missing-type-args", # missing type annotation
"missing-type-kwargs", # missing type annotation
"missing-return-type-private-function", # missing return type annotation
"docstring-missing-returns", # `return` is not documented in docstring
"blocking-open-call-in-async-function", # async functions should not open files with blocking methods like `open`
"hardcoded-bind-all-interfaces", # bind to all ports
"start-process-with-partial-path", # subprocess with partial path
]

[tool.ruff.format]
Expand Down
6 changes: 3 additions & 3 deletions src/aignostics_foundry_core/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class AuthSettings(OpaqueSettings):
internal_org_id: Annotated[str, StringConstraints(max_length=255, strip_whitespace=True)] = Field(default="")
role_claim: Annotated[str, StringConstraints(max_length=255, strip_whitespace=True)] = Field(default="")

def __init__(self, **kwargs: Any) -> None: # noqa: ANN401
def __init__(self, **kwargs: Any) -> None: # ruff: ignore[any-type]
"""Initialise settings, deriving env_prefix and env files from the active FoundryContext."""
ctx = get_context()
super().__init__(_env_prefix=f"{ctx.env_prefix}AUTH_", _env_file=ctx.env_file, **kwargs) # pyright: ignore[reportCallIssue]
Expand Down Expand Up @@ -354,7 +354,7 @@ async def _validate_jwt(token: str, auth_settings: AuthSettings) -> dict[str, An
issuer=f"https://{auth_settings.domain}/",
)
return payload
except Exception: # noqa: BLE001
except Exception: # ruff: ignore[blind-except]
logger.debug("JWT validation failed")
return None

Expand Down Expand Up @@ -617,7 +617,7 @@ async def me(user: Annotated[dict[str, Any], Depends(get_user)]):
try:
auth_client = get_auth_client(request)
session: dict = await auth_client.require_session(request, Response()) # type: ignore[reportUnknownVariableType]
except Exception: # noqa: BLE001
except Exception: # ruff: ignore[blind-except]
msg = "No session found"
logger.debug(msg)
return None
Expand Down
42 changes: 21 additions & 21 deletions src/aignostics_foundry_core/api/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def get_instances(cls) -> list[VersionedAPIRouter]:
"""
return cls._instances.copy()

def __new__(cls, version: str, *args: Any, **kwargs: Any) -> Self: # noqa: ANN401
def __new__(cls, version: str, *args: Any, **kwargs: Any) -> Self: # ruff: ignore[any-type]
"""Create a new instance with lazy-loaded dependencies.

Args:
Expand All @@ -79,15 +79,15 @@ def __new__(cls, version: str, *args: Any, **kwargs: Any) -> Self: # noqa: ANN4
Returns:
An instance of VersionedAPIRouter backed by a FastAPI APIRouter.
"""
from fastapi import APIRouter # noqa: PLC0415
from fastapi import APIRouter # ruff: ignore[import-outside-top-level]

class VersionedAPIRouterImpl(APIRouter):
"""Implementation of VersionedAPIRouter with lazy-loaded dependencies."""

version: str
exception_handlers: list[tuple[type[Exception], Any]]

def __init__(self, version: str, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
def __init__(self, version: str, *args: Any, **kwargs: Any) -> None: # ruff: ignore[any-type]
"""Initialise the router.

Args:
Expand All @@ -102,7 +102,7 @@ def __init__(self, version: str, *args: Any, **kwargs: Any) -> None: # noqa: AN
def add_exception_handler_registration(
self,
exc_class: type[Exception],
handler: Any, # noqa: ANN401
handler: Any, # ruff: ignore[any-type]
) -> None:
"""Register an exception handler to be added to the FastAPI app.

Expand Down Expand Up @@ -163,9 +163,9 @@ def create_authenticated_router(
Returns:
A configured APIRouter instance.
"""
from fastapi import Depends # noqa: PLC0415
from fastapi import Depends # ruff: ignore[import-outside-top-level]

from .auth import require_authenticated # noqa: PLC0415
from .auth import require_authenticated # ruff: ignore[import-outside-top-level]

actual_prefix = prefix if prefix is not None else f"/{module_tag}"
tags = [module_tag, API_TAG_AUTHENTICATED] + (extra_tags or [])
Expand Down Expand Up @@ -193,9 +193,9 @@ def create_admin_router(
Returns:
A configured APIRouter instance.
"""
from fastapi import Depends # noqa: PLC0415
from fastapi import Depends # ruff: ignore[import-outside-top-level]

from .auth import require_admin # noqa: PLC0415
from .auth import require_admin # ruff: ignore[import-outside-top-level]

actual_prefix = prefix if prefix is not None else f"/{module_tag}"
tags = [module_tag, API_TAG_ADMIN] + (extra_tags or [])
Expand Down Expand Up @@ -223,9 +223,9 @@ def create_internal_router(
Returns:
A configured APIRouter instance.
"""
from fastapi import Depends # noqa: PLC0415
from fastapi import Depends # ruff: ignore[import-outside-top-level]

from .auth import require_internal # noqa: PLC0415
from .auth import require_internal # ruff: ignore[import-outside-top-level]

actual_prefix = prefix if prefix is not None else f"/{module_tag}"
tags = [module_tag, API_TAG_INTERNAL] + (extra_tags or [])
Expand Down Expand Up @@ -253,9 +253,9 @@ def create_internal_admin_router(
Returns:
A configured APIRouter instance.
"""
from fastapi import Depends # noqa: PLC0415
from fastapi import Depends # ruff: ignore[import-outside-top-level]

from .auth import require_internal_admin # noqa: PLC0415
from .auth import require_internal_admin # ruff: ignore[import-outside-top-level]

actual_prefix = prefix if prefix is not None else f"/{module_tag}"
tags = [module_tag, API_TAG_INTERNAL_ADMIN] + (extra_tags or [])
Expand Down Expand Up @@ -283,9 +283,9 @@ def create_internal_superadmin_router(
Returns:
A configured APIRouter instance.
"""
from fastapi import Depends # noqa: PLC0415
from fastapi import Depends # ruff: ignore[import-outside-top-level]

from .auth import require_internal_superadmin # noqa: PLC0415
from .auth import require_internal_superadmin # ruff: ignore[import-outside-top-level]

actual_prefix = prefix if prefix is not None else f"/{module_tag}"
tags = [module_tag, API_TAG_INTERNAL_SUPERADMIN] + (extra_tags or [])
Expand Down Expand Up @@ -396,7 +396,7 @@ def get_versioned_api_instances(
Returns:
Mapping from version name to its configured ``FastAPI`` instance.
"""
from fastapi import FastAPI # noqa: PLC0415
from fastapi import FastAPI # ruff: ignore[import-outside-top-level]

ctx = context or get_context()
load_modules(context=ctx)
Expand All @@ -418,10 +418,10 @@ def get_versioned_api_instances(

def init_api(
root_path: str = "",
lifespan: Any | None = None, # noqa: ANN401
lifespan: Any | None = None, # ruff: ignore[any-type]
exception_handler_registrations: list[tuple[type[Exception], Any]] | None = None,
versions: list[str] | None = None,
**fastapi_kwargs: Any, # noqa: ANN401
**fastapi_kwargs: Any, # ruff: ignore[any-type]
) -> FastAPI:
"""Initialise a FastAPI application with standard exception handlers.

Expand Down Expand Up @@ -458,11 +458,11 @@ def init_api(
Returns:
A configured ``FastAPI`` instance.
"""
from fastapi import FastAPI # noqa: PLC0415
from fastapi.exceptions import RequestValidationError # noqa: PLC0415
from pydantic import ValidationError # noqa: PLC0415
from fastapi import FastAPI # ruff: ignore[import-outside-top-level]
from fastapi.exceptions import RequestValidationError # ruff: ignore[import-outside-top-level]
from pydantic import ValidationError # ruff: ignore[import-outside-top-level]

from aignostics_foundry_core.otel import instrument_fastapi # noqa: PLC0415
from aignostics_foundry_core.otel import instrument_fastapi # ruff: ignore[import-outside-top-level]

api = FastAPI(root_path=root_path, lifespan=lifespan, **fastapi_kwargs)

Expand Down
10 changes: 5 additions & 5 deletions src/aignostics_foundry_core/api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class _HasErrors(Protocol):
def errors(self) -> list[dict[str, Any]]: ...


class ApiException(Exception): # noqa: N818
class ApiException(Exception): # ruff: ignore[error-suffix-on-exception-name]
"""Base exception for API errors."""

status_code = 500
Expand Down Expand Up @@ -71,7 +71,7 @@ def api_exception_handler(_: "Request", exc: ApiException) -> "JSONResponse":
Returns:
JSONResponse with error details.
"""
from fastapi.responses import JSONResponse # noqa: PLC0415
from fastapi.responses import JSONResponse # ruff: ignore[import-outside-top-level]

return JSONResponse(
status_code=exc.status_code,
Expand All @@ -95,8 +95,8 @@ def unhandled_exception_handler(_: "Request", exc: Exception) -> "JSONResponse":
Returns:
JSONResponse with generic server error.
"""
from fastapi.responses import JSONResponse # noqa: PLC0415
from loguru import logger # noqa: PLC0415
from fastapi.responses import JSONResponse # ruff: ignore[import-outside-top-level]
from loguru import logger # ruff: ignore[import-outside-top-level]

logger.critical(f"Unhandled api exception {exc!r}", extra={"exception": f"{exc!r}"})
return JSONResponse(
Expand All @@ -118,7 +118,7 @@ def validation_exception_handler(_: "Request", exc: Exception) -> "JSONResponse"
Returns:
JSONResponse with validation error details.
"""
from fastapi.responses import JSONResponse # noqa: PLC0415
from fastapi.responses import JSONResponse # ruff: ignore[import-outside-top-level]

# Both ValidationError and RequestValidationError have errors() method
if isinstance(exc, _HasErrors):
Expand Down
2 changes: 1 addition & 1 deletion src/aignostics_foundry_core/boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def boot(
show_cmdline: Whether to include the process command line in the
boot log message (default: ``True``).
"""
global _boot_called # noqa: PLW0603
global _boot_called # ruff: ignore[global-statement]
if _boot_called:
return
_boot_called = True
Expand Down
2 changes: 1 addition & 1 deletion src/aignostics_foundry_core/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def _get_console() -> Console:
Console: The themed rich console.
"""
try:
from aignostics_foundry_core.foundry import get_context # noqa: PLC0415
from aignostics_foundry_core.foundry import get_context # ruff: ignore[import-outside-top-level]

env_var = f"{get_context().env_prefix}CONSOLE_WIDTH"
width: int | None = int(os.environ.get(env_var, "0")) or None
Expand Down
Loading
Loading