mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-10-31 10:02:38 +00:00
Plan rule 3c said every module this refactor creates is type-checked from its first commit; web_viewer/tracking.py was on the ignore list because it moved out of app.py with app's existing errors, and mypy skipped the bodies of untyped helpers in all the new modules. tracking.py is off the ignore list, and the 30 new modules get check_untyped_defs. The 25 errors that surfaced were all missing annotations: container annotations (paths_by_key, tracking, server_stats, result, daily_by_role, feed params), casts for page/page_size where pagination guarantees ints, FeedSubscriptionsMixin's two host attributes, and an ignore for Flask-SocketIO's request.sid. No runtime change.
253 lines
8.7 KiB
TOML
253 lines
8.7 KiB
TOML
# pyproject.toml
|
|
[build-system]
|
|
requires = ["setuptools>=61.0", "wheel"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[project]
|
|
name = "meshcore-bot"
|
|
version = "1.1.0"
|
|
description = "MeshCore Bot with commands for mesh testing, utilities, and service integration."
|
|
readme = "README.md"
|
|
# Table form rather than the SPDX string form: the string form needs
|
|
# setuptools>=77, above this project's declared build requirement.
|
|
license = { text = "MIT" }
|
|
authors = [{ name = "Adam Gessaman", email = "adam@gessaman.com" }]
|
|
requires-python = ">=3.10"
|
|
classifiers = [
|
|
"License :: OSI Approved :: MIT License",
|
|
"Programming Language :: Python :: 3",
|
|
"Operating System :: OS Independent",
|
|
]
|
|
dependencies = [
|
|
"pyserial>=3.5",
|
|
"bleak>=0.20.0",
|
|
"asyncio-mqtt>=0.11.0",
|
|
"configparser>=5.3.0",
|
|
"python-dateutil>=2.8.2",
|
|
"apscheduler>=3.10.0",
|
|
"colorlog>=6.7.0",
|
|
"requests>=2.31.0",
|
|
"urllib3>=2.0.0",
|
|
"pyephem>=4.1.4",
|
|
"geopy>=2.3.0",
|
|
"maidenhead>=1.4.0",
|
|
"pytz>=2023.3",
|
|
"aiohttp>=3.8.0",
|
|
# 2.3.14+ required for send_msg_with_retry's ACK handling (see requirements.txt)
|
|
"meshcore>=2.3.14",
|
|
"openmeteo-requests>=1.7.2",
|
|
"requests-cache>=1.1.1",
|
|
"retry-requests>=1.0.0",
|
|
"flask>=2.3.0",
|
|
"flask-socketio>=5.3.0",
|
|
"flask-compress>=1.14",
|
|
# Still required: `next_cmd` backs contact and channel operations that have no
|
|
# equivalent in the meshcore library yet (see requirements.txt).
|
|
"meshcore-cli>=1.4.0",
|
|
"feedparser>=6.0.10",
|
|
"paho-mqtt>=1.6.0",
|
|
"cryptography>=41.0.0",
|
|
"pynacl>=1.5.0",
|
|
"aiosqlite>=0.19.0",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
profanity = ["better-profanity>=0.7.0", "unidecode>=1.3.0"]
|
|
geo = ["pycountry>=23.12.0", "us>=2.0.0"]
|
|
lang = ["langdetect>=1.0.9"]
|
|
test = ["pytest>=7.0", "pytest-asyncio>=0.21", "pytest-mock>=3.10", "pytest-cov>=4.0", "pytest-timeout>=2.1.0", "types-requests>=2.31"]
|
|
docs = ["mkdocs-material>=9.0.0", "mkdocs-exclude>=1.0.0"]
|
|
|
|
[project.scripts]
|
|
meshcore-bot = "meshcore_bot:main"
|
|
meshcore-viewer = "modules.web_viewer.app:main"
|
|
|
|
[tool.setuptools]
|
|
py-modules = ["meshcore_bot"]
|
|
include-package-data = false
|
|
license-files = ["LICENSE"]
|
|
|
|
[tool.setuptools.packages.find]
|
|
where = ["."]
|
|
include = ["modules*", "translations*", "data*"]
|
|
exclude = ["tests*", "local*"]
|
|
|
|
[tool.setuptools.package-data]
|
|
modules = [
|
|
"web_viewer/templates/*.html",
|
|
"web_viewer/templates/**/*.html",
|
|
"web_viewer/static/*",
|
|
"web_viewer/static/*/*",
|
|
"web_viewer/static/*/*/*",
|
|
"templates/*.ini",
|
|
]
|
|
translations = ["*.json"]
|
|
"data.randomlines" = ["*.txt"]
|
|
|
|
[tool.ruff]
|
|
# Match CI/Makefile installs so lint rules do not drift on unpinned `pip install ruff`.
|
|
required-version = "==0.15.15"
|
|
line-length = 120
|
|
target-version = "py310"
|
|
exclude = [".venv", "build", "dist"]
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "W", "I", "UP", "B", "C4", "SIM"]
|
|
ignore = [
|
|
"E501", # line too long (handled by formatter)
|
|
# Legacy-code tolerances — pervasive in pre-typed source, not worth a bulk churn:
|
|
"E701", # multiple-statements-on-one-line-colon
|
|
"E702", # multiple-statements-on-one-line-semicolon
|
|
"E711", # comparison-to-none (== None common in legacy)
|
|
"E712", # comparison-to-true (== True/False common in legacy)
|
|
"E722", # bare-except (used extensively in graceful-degradation patterns)
|
|
"E741", # ambiguous-variable-name (l, O, I in legacy loops)
|
|
"E402", # module-level import not at top (conditional imports pattern)
|
|
"F601", # multi-value-repeated-key-literal (legacy dict pattern)
|
|
"B007", # unused-loop-control-variable (rename to _ is a bulk churn)
|
|
"B023", # function-uses-loop-variable (legacy closures in packet capture)
|
|
"B904", # raise-without-from-in-except (legacy raise pattern)
|
|
"C408", # unnecessary-collection-call
|
|
"C414", # unnecessary-double-cast-or-process
|
|
# pyupgrade rules that would require a bulk typing rewrite — deferred to a code-quality PR:
|
|
"UP007", # non-pep604-annotation-union (Union[X, Y] -> X | Y)
|
|
"UP035", # deprecated-import (typing.List/Dict/... remain prevalent)
|
|
"UP041", # timeout-error-alias (socket.timeout -> TimeoutError)
|
|
"UP045", # non-pep604-annotation-optional (Optional[X] -> X | None)
|
|
# Simplification suggestions — stylistic, not enforced on legacy code:
|
|
"SIM102", # collapsible-if
|
|
"SIM103", # needless-bool
|
|
"SIM105", # suppressible-exception
|
|
"SIM108", # if-else-block-instead-of-if-exp (ternary preference is subjective)
|
|
"SIM109", # compare-with-tuple
|
|
"SIM110", # reimplemented-builtin
|
|
"SIM114", # if-with-same-arms
|
|
"SIM115", # open-file-with-context-handler
|
|
"SIM117", # multiple-with-statements
|
|
"SIM210", # if-expr-with-true-false
|
|
]
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"tests/*" = ["S101"]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# mypy — incremental strict mode
|
|
# ---------------------------------------------------------------------------
|
|
# Global baseline: safe non-breaking options.
|
|
# Per-module overrides below tighten settings for fully-typed modules.
|
|
[tool.mypy]
|
|
python_version = "3.11"
|
|
ignore_missing_imports = true
|
|
warn_unused_ignores = true
|
|
warn_return_any = false # too noisy until all modules are annotated
|
|
warn_unused_configs = true
|
|
no_implicit_optional = true
|
|
strict_optional = true
|
|
|
|
# New modules written with full type annotations get strict treatment.
|
|
[[tool.mypy.overrides]]
|
|
module = [
|
|
"modules.alert_format",
|
|
"modules.commands.schedule_command",
|
|
"modules.service_plugins.webhook_service",
|
|
"modules.service_plugins.base_service",
|
|
"modules.message_handler",
|
|
"modules.utils",
|
|
"modules.plugin_loader",
|
|
"modules.security_utils",
|
|
"modules.commands.base_command",
|
|
"modules.commands.rain_command",
|
|
"modules.region_warning",
|
|
]
|
|
disallow_untyped_defs = true
|
|
disallow_incomplete_defs = true
|
|
check_untyped_defs = true
|
|
no_implicit_optional = true
|
|
|
|
# Modules with known type errors not yet brought up to strict standard.
|
|
# Suppress all mypy errors for these modules until they are fully annotated.
|
|
[[tool.mypy.overrides]]
|
|
module = [
|
|
"modules.core",
|
|
"modules.command_manager",
|
|
"modules.feed_manager",
|
|
"modules.mesh_graph",
|
|
"modules.scheduler",
|
|
"modules.maintenance",
|
|
"modules.transmission_tracker",
|
|
"modules.commands.alert_command",
|
|
"modules.commands.announcements_command",
|
|
"modules.commands.aurora_command",
|
|
"modules.commands.channels_command",
|
|
"modules.commands.greeter_command",
|
|
"modules.commands.help_command",
|
|
"modules.commands.joke_command",
|
|
"modules.commands.multitest_command",
|
|
"modules.commands.prefix_command",
|
|
"modules.commands.wx_command",
|
|
"modules.commands.alternatives.wx_international",
|
|
"modules.commands.trace_command",
|
|
"modules.commands.solarforecast_command",
|
|
"modules.commands.roll_command",
|
|
"modules.commands.repeater_command",
|
|
"modules.commands.path_command",
|
|
"modules.commands.sports_command",
|
|
"modules.commands.aqi_command",
|
|
"modules.service_plugins.discord_bridge_service",
|
|
"modules.service_plugins.packet_capture_service",
|
|
"modules.service_plugins.weather_service",
|
|
"modules.web_viewer.app",
|
|
"modules.web_viewer.integration",
|
|
]
|
|
ignore_errors = true
|
|
|
|
# Modules split out of the large files by the maintainability refactor: their
|
|
# untyped helper bodies are type-checked too, so a mixin's code is not silently
|
|
# skipped where the original method was.
|
|
[[tool.mypy.overrides]]
|
|
module = [
|
|
"modules.admin_server",
|
|
"modules.channel_message",
|
|
"modules.config_reload",
|
|
"modules.contact_events",
|
|
"modules.contacts_repo",
|
|
"modules.device_setup",
|
|
"modules.feed_parse",
|
|
"modules.joke_text",
|
|
"modules.logging_setup",
|
|
"modules.mesh_graph_recorder",
|
|
"modules.mesh_paths",
|
|
"modules.packet_decode",
|
|
"modules.radio_link",
|
|
"modules.radio_offline",
|
|
"modules.rf_correlation",
|
|
"modules.rf_log",
|
|
"modules.rf_match",
|
|
"modules.scope_gate",
|
|
"modules.service_plugins.channel_bridge_utils",
|
|
"modules.service_supervisor",
|
|
"modules.web_viewer.channels",
|
|
"modules.web_viewer.cleanup",
|
|
"modules.web_viewer.dashboard",
|
|
"modules.web_viewer.database_admin",
|
|
"modules.web_viewer.feeds",
|
|
"modules.web_viewer.live_stream",
|
|
"modules.web_viewer.mesh_evidence",
|
|
"modules.web_viewer.multibyte_rollout",
|
|
"modules.web_viewer.socket_clients",
|
|
"modules.web_viewer.tracking",
|
|
]
|
|
check_untyped_defs = true
|
|
|
|
# Pytest is configured in pytest.ini, not here. pytest.ini takes precedence over
|
|
# pyproject.toml, so a [tool.pytest.ini_options] block in this file would be dead
|
|
# config that silently drifts from the settings actually in effect.
|
|
|
|
[tool.coverage.run]
|
|
source = ["modules"]
|
|
omit = ["tests/*", ".venv/*"]
|
|
|
|
[tool.coverage.report]
|
|
fail_under = 50
|
|
show_missing = true
|