mirror of
https://github.com/kuhyx/signal-bot.git
synced 2026-11-10 19:27:20 +01:00
Some checks are pending
CI / check (push) Waiting to run
The commands were already live in the real group the moment the unit came up with the album loaded: _register_album registers pack:add and pack:random for every album, so nothing had to be enabled. What was missing is that nobody had been told, which is what a release is for. The changelog section is written the way the group reads it, and says the two things people will actually want to know: that a captioned photo lands in the album immediately, and that the location and phone model are cut out of it first and checked afterwards. Announced on the next restart, one message per group -- all four watched groups are at 0.2.0, so none of them gets a backlog. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqqE22jp94B1ypwxppdr1o
131 lines
3.9 KiB
TOML
131 lines
3.9 KiB
TOML
[project]
|
|
name = "signal-bot"
|
|
version = "0.2.1"
|
|
description = "A Signal group bot: image commands and daily message tallies."
|
|
readme = "README.md"
|
|
license = "MIT"
|
|
license-files = ["LICENSE"]
|
|
requires-python = ">=3.14"
|
|
|
|
# Exact pins, newest stable, per the dependency-freshness rule. A caret range
|
|
# is "newest-compatible" by definition and gives the freshness gate nothing to
|
|
# compare against.
|
|
dependencies = [
|
|
"fastapi==0.141.1",
|
|
"httpx==0.28.1",
|
|
"python-dotenv==1.2.3",
|
|
"PyYAML==6.0.3",
|
|
"uvicorn==0.52.4",
|
|
"websockets==17.1",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"mypy==2.3.1",
|
|
"pre-commit==4.6.2",
|
|
"pytest==9.1.1",
|
|
"pytest-asyncio==1.4.0",
|
|
"pytest-cov==7.1.0",
|
|
"ruff==0.16.5",
|
|
"types-PyYAML==6.0.12.20260815",
|
|
]
|
|
|
|
[project.scripts]
|
|
signal-bot = "signal_bot.__main__:main"
|
|
|
|
[build-system]
|
|
requires = ["setuptools==84.0.0"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[tool.setuptools]
|
|
packages = ["signal_bot", "fake_signal"]
|
|
|
|
# ============================================================================
|
|
# RUFF
|
|
# ============================================================================
|
|
[tool.ruff]
|
|
target-version = "py314"
|
|
line-length = 100
|
|
|
|
[tool.ruff.lint]
|
|
select = ["ALL"]
|
|
ignore = [
|
|
"D203", # conflicts with D211, we use D211
|
|
"D213", # conflicts with D212, we use D212
|
|
"COM812", # formatter owns trailing commas
|
|
"ISC001", # formatter may create implicit string concatenation
|
|
]
|
|
fixable = ["ALL"]
|
|
|
|
# Verified empirically, not copied: with this block removed, ruff reports
|
|
# exactly these four rules across tests/ and nothing else. SLF001 was in
|
|
# the original list and fired zero times, so it is gone.
|
|
[tool.ruff.lint.per-file-ignores]
|
|
# The single subprocess in this repository. S603 flags every subprocess call
|
|
# and has no code-level fix -- exiftool is a binary, and the pure-Python EXIF
|
|
# libraries handle neither HEIC nor MP4. signal_bot/external.py exists so this
|
|
# entry can name exactly one file: any other module that shells out fails the
|
|
# gate, which is the point. Do not widen this to a directory.
|
|
"signal_bot/external.py" = ["S603"]
|
|
"tests/**/*.py" = [
|
|
"ARG", # fixture and mock params exist for their side effect
|
|
"D", # test names are the documentation
|
|
"PLR2004", # `assert count == 2` beats a named constant
|
|
"S101", # assert IS what tests do
|
|
]
|
|
|
|
[tool.ruff.lint.pylint]
|
|
# The test envelope builder takes 7 keyword-only fields, one per envelope
|
|
# attribute. Splitting it into a dataclass would only move the count.
|
|
max-args = 7
|
|
|
|
[tool.ruff.lint.pydocstyle]
|
|
convention = "google"
|
|
|
|
[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"
|
|
docstring-code-format = true
|
|
|
|
# ============================================================================
|
|
# MYPY
|
|
# ============================================================================
|
|
[tool.mypy]
|
|
python_version = "3.14"
|
|
strict = true
|
|
warn_unreachable = true
|
|
disallow_any_explicit = false
|
|
|
|
# ============================================================================
|
|
# PYTEST / COVERAGE
|
|
# ============================================================================
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
asyncio_mode = "auto"
|
|
asyncio_default_fixture_loop_scope = "function"
|
|
addopts = [
|
|
"--cov=signal_bot",
|
|
"--cov=fake_signal",
|
|
"--cov-branch",
|
|
"--cov-report=term-missing",
|
|
"--cov-fail-under=100",
|
|
"--strict-markers",
|
|
]
|
|
|
|
[tool.coverage.run]
|
|
branch = true
|
|
# No omits. Every line of both packages is covered by tests.
|
|
|
|
[tool.coverage.report]
|
|
# No "pragma: no cover" escape hatch: nothing in this repo uses one, and
|
|
# leaving the pattern configured is an invitation to hide code from the
|
|
# 100% gate later. TYPE_CHECKING bodies are genuinely never executed.
|
|
exclude_lines = ["if TYPE_CHECKING:"]
|
|
show_missing = true
|