mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:27:02 +01:00
github.com/kuhyx/system-maintenance, cloned to ~/system-maintenance First of the four live subsystems, and the one with no cross-unit source edges, so it establishes the pattern for the harder three. Passed in vmbox first -- the installer ran from an extracted-layout copy in the guest and detected its distro without any monorepo path -- then on the host. Its 21 Python and shell test files lived in linux_configuration/tests/, reaching bin/ through a shared conftest. Twenty moved with the code and got their own conftest; the shared one stays, since it serves several script directories that are not going anywhere. test_shutdown_timer_monitor.sh stays here. It is a pair test: it checks that digital_wellbeing's installer template and the monitor it installs still agree, so it belongs to whichever half owns the installer. It now reads the monitor from ~/system-maintenance and SKIPs when that checkout is absent. An intermediate version of that test fell back to /usr/local/bin, which HUNG -- the installed copy is stale and differs from source, so the test was comparing an installer template against a binary it never generated. Falling back to it would have been worse than skipping, so the fallback is gone and the comment says why. Also removed test_hosts_file_monitor.sh from shell-tests.yml's explicit list: it left with the subsystem, and CI would have failed on the missing file rather than quietly skipping it. Verified: 136 tests pass in the new repo, 202 still pass here, the pair test passes against the checkout and skips without it, and both the shell coverage gate and shellcheck are clean. Depth 294 -> 267. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
390 lines
15 KiB
TOML
390 lines
15 KiB
TOML
[project]
|
|
name = "testsandmisc"
|
|
version = "0.1.0"
|
|
description = "Collection of miscellaneous tests and scripts"
|
|
requires-python = ">=3.10"
|
|
|
|
# ============================================================================
|
|
# RUFF - Extremely fast Python linter and formatter (written in Rust)
|
|
# ============================================================================
|
|
[tool.ruff]
|
|
target-version = "py310"
|
|
# Include all Python files
|
|
include = ["*.py", "**/*.py"]
|
|
# Exclude vendored/build directories
|
|
exclude = [
|
|
".git",
|
|
".venv",
|
|
"__pycache__",
|
|
"build",
|
|
"dist",
|
|
".eggs",
|
|
"Bash/ffmpeg-build", # Vendored FFmpeg tools
|
|
]
|
|
|
|
[tool.ruff.lint]
|
|
# AGGRESSIVE: Select ALL rules from all categories
|
|
select = ["ALL"]
|
|
# Ignores for rules that are too strict for this mixed script repository
|
|
ignore = [
|
|
# D203 vs D211 conflict - we use D211 (no blank line before class docstring)
|
|
"D203", # 1 blank line required before class docstring (conflicts with D211)
|
|
# D212 vs D213 conflict - we use D212 (summary on first line after """)
|
|
"D213", # Multi-line docstring summary should start at second line (conflicts with D212)
|
|
# Formatter conflicts - recommended to disable when using ruff format
|
|
# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
|
|
"COM812", # Trailing comma missing - formatter handles this automatically
|
|
"ISC001", # Implicit string concatenation - formatter may create these when wrapping
|
|
# Security audit - prone to false positives with validated input
|
|
# https://github.com/astral-sh/ruff/issues/4045
|
|
"S603", # subprocess call without shell - prone to false positives as it is
|
|
# difficult to determine whether the passed arguments have been validated
|
|
]
|
|
|
|
# Allow ALL rules to be auto-fixed
|
|
fixable = ["ALL"]
|
|
unfixable = []
|
|
|
|
# Per-file ignores — only rules that FUNDAMENTALLY conflict with test code remain.
|
|
# Every other rule was fixed in source. See justifications below.
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"**/code_tutor/cli.py" = [
|
|
"B008", # typer.Argument(...) as a parameter default is the standard Typer
|
|
# dependency-injection pattern, not a mutable-default bug.
|
|
]
|
|
"**/tests/**/*.py" = [
|
|
"ARG", # @patch decorators inject mock params that aren't always referenced;
|
|
# the patch side-effect is needed, not the mock object itself.
|
|
"D", # Test names like test_sub_cards_no_answer_text are self-documenting;
|
|
# docstrings would be redundant noise on every test method.
|
|
"PLC0415", # Test isolation requires importing AFTER mocking sys.modules;
|
|
# top-level imports would bypass the mocks entirely.
|
|
"PLR2004", # assert count == 5 is clearer than assert count == EXPECTED_COUNT;
|
|
# named constants for test expectations add indirection without value.
|
|
"S101", # assert IS what tests do — every Python test suite suppresses this.
|
|
"SLF001", # Unit tests must exercise private internals (_method, _attr) to reach
|
|
# 100% branch coverage; only integration tests can avoid this.
|
|
"TC002", # pytest resolves fixture parameter annotations at RUNTIME, so moving
|
|
"TC003", # pytest/Path into a TYPE_CHECKING block breaks collection. Verified
|
|
# empirically: guarding them failed 11 tests with UnboundLocalError
|
|
# and NameError, not a hypothetical concern.
|
|
]
|
|
"**/test_*.py" = [
|
|
"ARG",
|
|
"D",
|
|
"PLC0415",
|
|
"PLR2004",
|
|
"S101",
|
|
"SLF001",
|
|
]
|
|
|
|
|
|
[tool.ruff.lint.pylint]
|
|
max-args = 6 # code_tutor challenge flows genuinely need 6 params
|
|
max-returns = 8 # challenge state machines have multiple exit paths
|
|
|
|
[tool.ruff.lint.pydocstyle]
|
|
convention = "google" # Use Google docstring convention
|
|
|
|
[tool.ruff.lint.isort]
|
|
force-single-line = false
|
|
force-sort-within-sections = true
|
|
known-first-party = ["python_pkg"]
|
|
|
|
[tool.ruff.lint.flake8-quotes]
|
|
docstring-quotes = "double"
|
|
inline-quotes = "double"
|
|
|
|
[tool.ruff.lint.flake8-tidy-imports]
|
|
ban-relative-imports = "all"
|
|
|
|
[tool.ruff.format]
|
|
quote-style = "double"
|
|
indent-style = "space"
|
|
skip-magic-trailing-comma = false
|
|
line-ending = "auto"
|
|
docstring-code-format = true
|
|
|
|
# ============================================================================
|
|
# MYPY - Static type checker (most aggressive settings)
|
|
# ============================================================================
|
|
[tool.mypy]
|
|
python_version = "3.10"
|
|
# Strict mode enables most checks
|
|
strict = true
|
|
# Additional aggressive settings
|
|
warn_return_any = true
|
|
warn_unused_configs = true
|
|
disallow_untyped_defs = true
|
|
disallow_incomplete_defs = true
|
|
check_untyped_defs = true
|
|
disallow_untyped_decorators = true
|
|
no_implicit_optional = true
|
|
warn_redundant_casts = true
|
|
warn_unused_ignores = true
|
|
warn_no_return = true
|
|
warn_unreachable = true
|
|
# Extra strict settings
|
|
disallow_any_unimported = true
|
|
disallow_any_explicit = false # Too aggressive for practical use
|
|
disallow_any_generics = true
|
|
disallow_subclassing_any = true
|
|
strict_equality = true
|
|
extra_checks = true
|
|
# Allow missing imports for third-party packages
|
|
ignore_missing_imports = true
|
|
# Show error codes
|
|
show_error_codes = true
|
|
# Enable colored output
|
|
color_output = true
|
|
# Exclude vendored directories
|
|
exclude = [
|
|
"Bash/ffmpeg-build/",
|
|
".venv/",
|
|
"linux_configuration/scripts/single_use/misc/testsAndMisc-bash/tools/", # Avoid duplicate module named 'tools'
|
|
]
|
|
|
|
# Standalone tool scripts outside python_pkg/ are not held to strict mypy rules
|
|
[[tool.mypy.overrides]]
|
|
module = "linux_configuration.*"
|
|
ignore_errors = true
|
|
|
|
# External libraries without bundled stubs - suppress import-untyped errors
|
|
[[tool.mypy.overrides]]
|
|
module = ["requests.*", "rich.*", "anthropic.*", "typer.*"]
|
|
ignore_missing_imports = true
|
|
|
|
# code_tutor uses TYPE_CHECKING-only imports for rich/typer; types propagate as
|
|
# Any at call sites because those libs lack complete stubs in this env.
|
|
# untyped-decorator fires for @app.command() which is a Typer pattern.
|
|
[[tool.mypy.overrides]]
|
|
module = "python_pkg.code_tutor.*"
|
|
disallow_any_unimported = false
|
|
disallow_untyped_decorators = false
|
|
|
|
# ============================================================================
|
|
# PYLINT - Comprehensive Python linter
|
|
# ============================================================================
|
|
[tool.pylint.main]
|
|
# Make standalone script dirs importable so tests that import their modules by
|
|
# bare name (the same dirs linux_configuration/tests/conftest.py adds to
|
|
# sys.path at runtime) resolve under static analysis instead of raising E0401.
|
|
# Paths are relative to the repo root, which is pre-commit's working directory.
|
|
init-hook = "import sys; sys.path[:0] = ['meta/scripts', 'python_pkg', 'phone_focus_mode', 'phone_focus_mode/lib', 'linux_configuration/scripts/single_use/utils', 'linux_configuration/scripts/periodic_background/digital_wellbeing', 'linux_configuration/scripts/single_use/misc/testsAndMisc-bash/tools']"
|
|
# Analyse import fallback blocks
|
|
analyse-fallback-blocks = true
|
|
# Pickle collected data for later comparisons
|
|
persistent = true
|
|
# Jobs to use for parallel execution (0 = auto)
|
|
jobs = 0
|
|
# Minimum Python version
|
|
py-version = "3.10"
|
|
# Ignore vendored directories. "tests" and "conftest.py" are basename
|
|
# matches: test suites and pytest fixtures intentionally use patterns
|
|
# (protected-access, missing docstrings, fixture-arg shadowing) that don't
|
|
# apply to source code, so they are linted separately (not by this hook).
|
|
ignore = ["Bash", ".venv", "__pycache__", "tests", "conftest.py"]
|
|
# Ignore patterns
|
|
ignore-patterns = [".*\\.pyi$"]
|
|
# Allow C extension modules to be introspected
|
|
extension-pkg-allow-list = ["cv2", "pygame", "lxml"]
|
|
|
|
[tool.pylint.messages_control]
|
|
# Enable all checks by disabling disable
|
|
enable = "all"
|
|
# Globally disabled checks. Each is either a stylistic preference that conflicts
|
|
# with deliberate, clearer code, or a structural false positive that cannot be
|
|
# rewritten without harming readability. Everything else stays at max strictness.
|
|
disable = [
|
|
# use-implicit-booleaness family (C1803/C1804/C1805): pylint wants
|
|
# `not x` / `not s` instead of `x == 0` / `s == ""`. Explicit comparisons
|
|
# against 0 and "" state numeric/string intent more clearly than truthiness
|
|
# (and are not equivalent when the value may be None), so we keep them.
|
|
"use-implicit-booleaness-not-comparison",
|
|
"use-implicit-booleaness-not-comparison-to-string",
|
|
"use-implicit-booleaness-not-comparison-to-zero",
|
|
# consider-using-with (R1732): several subprocess.Popen calls are
|
|
# intentionally fire-and-forget — the process must outlive the calling
|
|
# scope and is polled/killed later, so a `with` block is wrong here.
|
|
"consider-using-with",
|
|
# unnecessary-ellipsis (W2301): Protocol abstract method bodies use `...`
|
|
# by Python convention (PEP 544); `pass` is equivalent but less idiomatic.
|
|
"unnecessary-ellipsis",
|
|
]
|
|
|
|
[tool.pylint.design]
|
|
# Mixins and single-entry-point classes may have zero public methods
|
|
min-public-methods = 0
|
|
# Test modules can be large
|
|
max-module-lines = 1000
|
|
# UI/mixin classes accumulate attributes across multiple mixins
|
|
max-attributes = 12
|
|
# code_tutor challenge flows genuinely need 6 params (matches ruff max-args)
|
|
max-args = 6
|
|
max-positional-arguments = 6
|
|
# Complex lesson/challenge functions need up to 20 locals
|
|
max-locals = 20
|
|
|
|
[tool.pylint.basic]
|
|
# Allow standard snake_case methods AND AST NodeVisitor visit_CapWords methods
|
|
method-rgx = "[a-z_][a-z0-9_]{2,}$|visit_[A-Za-z][A-Za-z0-9_]*"
|
|
|
|
[tool.pylint.similarities]
|
|
# 6 lines: CodeItem and ItemData share id/file/type/name/start_line/end_line fields
|
|
# intentionally (mirror the same domain schema). Raise the threshold so pylint
|
|
# doesn't flag this intentional structural duplication.
|
|
min-similarity-lines = 10
|
|
|
|
[tool.pylint.spelling]
|
|
# No spelling dictionary to avoid false positives
|
|
spelling-dict = ""
|
|
|
|
[tool.pylint.typecheck]
|
|
# cv2 (OpenCV) dynamically loads members from C extension at runtime.
|
|
# unittest.mock.MagicMock generates assertion/introspection methods at runtime.
|
|
# wave.open(path, "wb") returns a Wave_write, but pylint's stdlib stub infers the
|
|
# read-mode Wave_read overload and wrongly reports its setter/writer methods as
|
|
# missing — list them so the write API is recognised.
|
|
generated-members = [
|
|
"cv2.*",
|
|
".*\\.assert_called_once_with",
|
|
".*\\.assert_called_once",
|
|
".*\\.assert_called",
|
|
".*\\.assert_not_called",
|
|
".*\\.assert_any_call",
|
|
".*\\.call_args",
|
|
".*\\.call_args_list",
|
|
".*\\.call_count",
|
|
".*\\.setnchannels",
|
|
".*\\.setsampwidth",
|
|
".*\\.setframerate",
|
|
".*\\.writeframes",
|
|
".*\\.writeframesraw",
|
|
]
|
|
|
|
# ============================================================================
|
|
# BANDIT - Security linter
|
|
# ============================================================================
|
|
[tool.bandit]
|
|
# Exclude test directories and vendored code
|
|
exclude_dirs = ["tests", ".venv", "Bash/ffmpeg-build"]
|
|
|
|
# ============================================================================
|
|
# BLACK & ISORT - Removed (ruff handles formatting and import sorting)
|
|
# ============================================================================
|
|
|
|
# ============================================================================
|
|
# PYTEST - Testing framework configuration
|
|
# ============================================================================
|
|
[tool.pytest.ini_options]
|
|
# linux_configuration/tests covers the standalone usage_report scripts. It adds
|
|
# no python_pkg coverage (those tests don't import python_pkg), so running it
|
|
# alongside leaves the 100%-on-python_pkg gate untouched.
|
|
testpaths = ["python_pkg", "linux_configuration/tests"]
|
|
python_files = ["test_*.py", "*_test.py"]
|
|
python_classes = ["Test*"]
|
|
python_functions = ["test_*"]
|
|
addopts = [
|
|
"-v",
|
|
"--strict-markers",
|
|
"--strict-config",
|
|
"-ra",
|
|
"--cov=python_pkg",
|
|
"--cov-branch",
|
|
"--cov-report=term-missing",
|
|
"--cov-report=lcov",
|
|
]
|
|
filterwarnings = [
|
|
"error",
|
|
"ignore::DeprecationWarning",
|
|
"default::pytest.PytestUnraisableExceptionWarning",
|
|
]
|
|
|
|
# ============================================================================
|
|
# COVERAGE - Code coverage configuration
|
|
# ============================================================================
|
|
[tool.coverage.run]
|
|
source = ["python_pkg"]
|
|
branch = true
|
|
omit = [
|
|
"*/__pycache__/*",
|
|
"*/tests/*",
|
|
"*/.venv/*",
|
|
]
|
|
|
|
[tool.coverage.report]
|
|
# Fail under this percentage
|
|
fail_under = 100
|
|
show_missing = true
|
|
skip_covered = false
|
|
exclude_lines = [
|
|
# Standard exclusions
|
|
"pragma: no cover",
|
|
# Unreachable defensive code
|
|
"raise NotImplementedError",
|
|
"raise AssertionError",
|
|
# Type checking imports
|
|
"if TYPE_CHECKING:",
|
|
# Main script entry point
|
|
'if __name__ == "__main__":',
|
|
]
|
|
# Partial branch exclusions for unreachable branches
|
|
partial_branches = [
|
|
"pragma: no branch",
|
|
]
|
|
|
|
# ============================================================================
|
|
# VULTURE - Dead code detection
|
|
# ============================================================================
|
|
# Note: Vulture uses command-line args, but we can document settings here
|
|
# vulture --min-confidence 80 --exclude ".venv,Bash" .
|
|
|
|
# ============================================================================
|
|
# FLAKE8 - Python linter (via Flake8-pyproject for pyproject.toml support)
|
|
# ============================================================================
|
|
[tool.flake8]
|
|
# Maximum line length (matches ruff/black)
|
|
max-line-length = 88
|
|
# Maximum McCabe complexity (matches ruff C901 threshold)
|
|
max-complexity = 10
|
|
# Maximum cognitive complexity (flake8-cognitive-complexity)
|
|
max-cognitive-complexity = 12
|
|
# Maximum function length (flake8-functions)
|
|
max-function-length = 20
|
|
# Maximum returns/arguments per function
|
|
max-returns-amount = 6
|
|
max-arguments = 5
|
|
# Docstring convention (matches ruff)
|
|
docstring-convention = "google"
|
|
# Select all error codes
|
|
select = ["E", "F", "W", "C", "B", "B950"]
|
|
# Extend with plugin codes
|
|
extend-select = ["B", "B9", "C4", "SIM", "PT", "TC", "ANN"]
|
|
# Ignore rules that conflict with ruff-format or are duplicated
|
|
extend-ignore = [
|
|
"E501", # Line too long - B950 from bugbear is smarter (allows 10% overflow)
|
|
"W503", # Line break before binary operator - contradicts PEP 8 update
|
|
"ANN101", # Missing type annotation for self
|
|
"ANN102", # Missing type annotation for cls
|
|
]
|
|
# Exclude directories
|
|
exclude = [
|
|
".git",
|
|
".venv",
|
|
"__pycache__",
|
|
"build",
|
|
"dist",
|
|
".eggs",
|
|
"Bash/ffmpeg-build",
|
|
]
|
|
# Per-file ignores
|
|
per-file-ignores = [
|
|
"**/tests/**/*.py:S101,ANN",
|
|
"**/test_*.py:S101,ANN",
|
|
]
|
|
|
|
# ============================================================================
|
|
# PYDOCSTYLE - Docstring style checker (ruff handles this, but for standalone)
|
|
# ============================================================================
|
|
# Configured in ruff.lint.pydocstyle above
|