pyproject.toml
Rama main · réplica de lectura del repositorio original.
[project]
name = "topic-watch"
version = "1.5.3"
description = "Self-hosted news watchdog with AI-powered novelty detection"
license = "GPL-3.0-or-later"
readme = "README.md"
authors = [{ name = "0xzerolight" }]
maintainers = [{ name = "0xzerolight" }]
keywords = ["rss", "news", "llm", "notifications", "self-hosted", "novelty-detection"]
requires-python = ">=3.11"
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Web Environment",
"Framework :: FastAPI",
"Intended Audience :: End Users/Desktop",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP :: Indexing/Search",
"Topic :: Communications",
"Topic :: Office/Business :: News/Diary",
]
dependencies = [
"fastapi>=0.115,<1.0",
"uvicorn[standard]>=0.32,<1.0",
"jinja2>=3.1,<4.0",
"markdown-it-py>=3.0,<5.0",
"litellm>=1.50,<2.0",
"instructor>=1.7,<2.0",
"tenacity>=8.2.3,<10.0",
"feedparser>=6.0,<7.0",
"httpx>=0.27,<1.0",
"trafilatura>=2.0,<3.0",
"apprise>=1.9,<2.0",
"apscheduler>=3.10,<4.0",
"pydantic>=2.10,<3.0",
"pydantic-settings[yaml]>=2.7,<3.0",
"python-multipart>=0.0.9,<1.0",
]
[project.scripts]
topic-watch = "app.cli:main"
[project.urls]
Homepage = "https://github.com/0xzerolight/topic_watch"
Repository = "https://github.com/0xzerolight/topic_watch"
Issues = "https://github.com/0xzerolight/topic_watch/issues"
[project.optional-dependencies]
dev = [
"pytest>=8.0,<10.0",
"pytest-asyncio>=0.24,<2.0",
"pytest-cov>=6.0,<8.0",
"ruff>=0.8,<1.0",
"mypy>=1.13,<3.0",
"pre-commit>=4.0,<5.0",
"types-PyYAML>=6.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["app"]
[tool.ruff]
target-version = "py311"
line-length = 120
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes
"W", # pycodestyle warnings
"I", # isort (import sorting)
"UP", # pyupgrade
"B", # flake8-bugbear
"SIM", # flake8-simplify
"N", # pep8-naming
"S", # flake8-bandit (security)
"T20", # flake8-print (no print statements)
]
ignore = [
"E501", # line too long (handled by formatter)
"B008", # do not perform function calls in argument defaults (needed for FastAPI Depends())
"N818", # exception name should end in Error (not always appropriate)
"S101", # assert usage (used intentionally in app for invariant checks)
"S608", # SQL injection false positive (we use parameterized queries)
"S704", # Markup usage is intentional and pre-escaped
]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["B011", "S101", "S105"] # allow asserts and test secrets in tests
"app/cli.py" = ["T201"] # CLI is supposed to print output
"evals/__main__.py" = ["T201"] # the eval harness CLI prints its output too
"scripts/*.py" = ["T201"] # badge scripts write their output to stdout
"app/migrations/**/*.py" = ["E501"] # migrations can have long lines
[tool.ruff.lint.isort]
known-first-party = ["app", "evals"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = true
check_untyped_defs = true
disallow_untyped_defs = false
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
addopts = "--cov=app --cov-report=term-missing --cov-fail-under=85"