[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "laborious" version = "0.0.0" description = "Sientia DataOps Laborious - ML Model Orchestration System" readme = "README.md" requires-python = ">=3.11" authors = [ {name = "Aignosi", email = "dev@aignosi.com"} ] [tool.ruff] line-length = 100 target-version = "py311" exclude = [ ".git", ".venv", "venv", "__pycache__", "*.pyc", ".pytest_cache", "htmlcov", "tests/laborious/workflows/subworkflows/test_prediction_process.py", ] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "B", # flake8-bugbear "C4", # flake8-comprehensions "UP", # pyupgrade "N", # pep8-naming "YTT", # flake8-2020 "S", # flake8-bandit "BLE", # flake8-blind-except "A", # flake8-builtins "C90", # mccabe complexity ] ignore = [ "BLE001", # ignore blind except, we need to send notifications with any error "E501", # line too long (handled by formatter) "S101", # use of assert (needed for tests) "S105", # possible hardcoded password (false positives) "S106", # possible hardcoded password (false positives) "S608", # potential sql injection (false positives) "N802", # function name should be lowercase (temporal decorators) "N806", # variable in function should be lowercase ] [tool.ruff.lint.per-file-ignores] "tests/**/*.py" = [ "S101", # assert allowed in tests "S105", # hardcoded passwords ok in tests "S106", # hardcoded passwords ok in tests ] "e2e/conftest.py" = [ # Imports below the sientia/ModelAnalysis stub are load-order critical: the stub # must be in sys.modules before Activities is imported, so they cannot move up. "E402", ] "scripts/**/*.py" = [ # Notebook-style scripts split into `# %%` cells: each cell imports what it needs # where it needs it, so imports legitimately appear below other statements. "E402", ] [tool.ruff.lint.mccabe] max-complexity = 15 [tool.ruff.format] quote-style = "single" indent-style = "space" line-ending = "auto" [tool.mypy] python_version = "3.11" warn_return_any = false warn_unused_configs = true disallow_untyped_defs = false disallow_incomplete_defs = false check_untyped_defs = true no_implicit_optional = true warn_redundant_casts = true warn_unused_ignores = false warn_no_return = true strict_equality = true ignore_missing_imports = true # Ignore missing imports for external packages [[tool.mypy.overrides]] module = "temporalio.*" ignore_missing_imports = true [[tool.mypy.overrides]] module = "sientia_do.*" ignore_missing_imports = true [[tool.mypy.overrides]] module = "mlflow.*" ignore_missing_imports = true [[tool.mypy.overrides]] module = "prometheus_client.*" ignore_missing_imports = true [[tool.mypy.overrides]] module = "sientia.*" ignore_missing_imports = true [[tool.mypy.overrides]] module = "pandas.*" ignore_missing_imports = true [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] addopts = [ "-v", "--strict-markers", # pytest>=9.1 has a known bug where its unraisableexception plugin crashes # (tracemalloc partially-initialized AttributeError) when 2+ unraisable # exceptions land close together — e.g. "coroutine was never awaited" from # AsyncMock-mocked sync methods (metrics_controller, minio_repository) being # GC'd. Harmless mock artifacts turned into a hard ERROR by the plugin itself. "-p", "no:unraisableexception", ] filterwarnings = [ # `kafka-python`, pulled in transitively by `sientia_do`, reads its protocol schemas through the # legacy `importlib.resources` API that Python 3.11 deprecated. It emits ~109 warnings per run, # twice each (once at the call site, once inside `importlib`), which is enough noise to bury a # warning worth reading. Nothing here can fix it — the change belongs in `kafka-python`. # # Matched on the message rather than by module so the filter cannot quietly swallow an unrelated # deprecation: any *other* DeprecationWarning, including one from our own code, still shows up. "ignore:read_text is deprecated:DeprecationWarning", "ignore:open_text is deprecated:DeprecationWarning", ] markers = [ "asyncio: marks tests as async", "integration: marks tests as integration tests", "unit: marks tests as unit tests", "opc: marks tests that use the in-process OPC UA server (OpcRepository E2E)", # The .sientia import e2e suite. Outside `testpaths`, so `validate --only-tests` and the # coverage gate never collect it; run it on request with `pytest e2e -m import_e2e`. "import_e2e: marks the model-import end-to-end tests (needs Docker and an MLflow server)", "slow: marks tests that run on a real clock and take tens of seconds", ] [tool.coverage.run] source = ["laborious"] omit = [ "*/tests/*", "*/venv/*", "*/__pycache__/*", "*/site-packages/*", ] branch = true [tool.coverage.report] precision = 2 show_missing = true skip_covered = false exclude_lines = [ "pragma: no cover", "def __repr__", "def __str__", "raise AssertionError", "raise NotImplementedError", "if __name__ == .__main__.:", "if TYPE_CHECKING:", "class .*\\bProtocol\\):", "@(abc\\.)?abstractmethod", ] [tool.coverage.html] directory = "htmlcov" [tool.bandit] exclude_dirs = ["tests", "venv", ".venv"] skips = ["B101", "B601", "B608"] # Skip assert, shell injection, and SQL injection (false positives)