signal-bot/pyproject.toml
Krzysztof kuhy Rudnicki be24243507 release: 0.1.0 «Hygin» — the statistics release
The tally becomes a message history. Ordinal 9 lands on 0.1.0 by
arithmetic rather than by choice, which is a pleasant coincidence for a
release this size.

What changes for the group, in the four bullets they will read: photos
and videos now count (a caption-less photo was worth zero, so everyone's
numbers jumped), people who said nothing appear at 0, nine new commands,
and the bot remembers history from 30 August 2026.

What changes underneath: an append-only per-message log holding metadata
and never a body; days that are calendar days in Europe/Warsaw rather
than "since the last post"; records, crown streaks and weekday averages;
weekly and monthly summaries; and reports that survive an outage instead
of being lost.

Exercised in testbot before this bump, per DOCS-changelog.md: all nine
commands ran clean, and kuhy confirmed the rendering on a real phone --
the one check that could not be done from here, since Signal's
proportional font is why the columns are separated by a dash rather than
padded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d48t4qsQLBJnDwDeo2Nom
2026-08-30 20:00:58 +02:00

125 lines
3.5 KiB
TOML

[project]
name = "signal-bot"
version = "0.1.0"
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]
"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