[project] readme = "README.md" name = "ai-marketplace-monitor" version = "0.9.11" description = "An AI-based tool for monitoring facebook marketplace" authors = [{ name = "Bo Peng", email = "ben.bob@gmail.com" }] requires-python = ">=3.10" keywords = ["ai-marketplace-monitor"] classifiers = [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Affero General Public License v3", "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ] dependencies = [ "typer>=0.15.1,<0.18.0", "playwright>=1.41.0", "rich>=13.7.0", "pushbullet.py>=0.12.0", "diskcache>=5.6.3", "watchdog>=4.0.0", "openai>=1.24.0", "parsedatetime>=2.5", "humanize>=4.0.0", "schedule>=1.2.2", "inflect>=7.0.0", "pillow>=10.0.0", "jinja2>=3.0.0", "pyparsing>=3.1.0", "requests>=2.30.0", "CurrencyConverter>=0.18.0", "tomli==2.2.1; python_version < '3.11'", "safety>=3.5.2", "pip-audit>=2.9.0", "python-telegram-bot>=22.3", ] [project.urls] Homepage = "https://github.com/BoPeng/ai-marketplace-monitor" Repository = "https://github.com/BoPeng/ai-marketplace-monitor" Documentation = "https://ai-marketplace-monitor.readthedocs.io" "Bug Tracker" = "https://github.com/BoPeng/ai-marketplace-monitor/issues" [project.scripts] ai-marketplace-monitor = "ai_marketplace_monitor.cli:app" aimm = "ai_marketplace_monitor.cli:app" [project.optional-dependencies] pynput = ["pynput>=1.7.0"] dev = [ "pre-commit>=4.0.1", "invoke>=2.2.0", "bump2version>=1.0.1", "watchdog[watchmedo]>=6.0.0", "pip-audit>=2.9.0", "build>=1.0.0", "twine>=5.0.0", ] test = [ "pytest>=8.3.3", "xdoctest>=1.2.0", "coverage[toml]>=7.6.7", "pytest-cov>=6.0.0", "pytest-playwright>=0.7.0", ] linters = ["isort>=5.13.2,<7.0.0", "black>=24.10,<26.0", "ruff>=0.9.2,<0.14.0"] security = ["safety>=3.2.11"] typing = ["mypy>=1.13.0"] docs = [ "sphinx>=8.1.3", "furo>=2024.1.29", "myst-parser>=3.0.0", "sphinx-copybutton>=0.5.2", "sphinxext-opengraph>=0.9.0", "linkify-it-py>=2.0.0", ] [tool.coverage.paths] source = ["src", "*/site-packages"] [tool.coverage.run] branch = true source = ["ai_marketplace_monitor"] [tool.coverage.report] fail_under = 100 exclude_lines = [ "pragma: no cover", "def __repr__", "if self.debug", "if settings.DEBUG:", "raise AssertionError", "raise NotImplementedError", "if 0:", "if __name__ == __main__:", ] show_missing = true [tool.coverage.html] directory = "htmlcov" [tool.pytest.ini_options] asyncio_mode = "auto" filterwarnings = [ # Suppress AsyncMock coroutine warnings in Telegram notification tests # These warnings occur when testing sync methods that wrap async operations with asyncio.run() # The coroutines are properly handled by asyncio.run() but pytest's garbage collection # triggers warnings for the mock coroutines that were never directly awaited "ignore::RuntimeWarning:_pytest.unraisableexception", "ignore:coroutine.*was never awaited:RuntimeWarning", ] [tool.ruff] target-version = "py39" output-format = "full" line-length = 99 fix = true extend-exclude = ["docs/*"] [tool.ruff.lint] ignore = [ "ANN202", # **kwargs: Any "ANN401", "ANN002", "ANN003", "E722", "G004", "S311", "B017", "S105", # hardcoded passwords (false positives in test data) "S106", "G003", "S101", # use of assert "BLE001", # blank exception "C901", # too complex (function name too long etc) "D100", # docstring "D101", # docstring "D102", # docstring "D103", # docstring "D107", # docstring "D415", # docstring "ERA001", # commented code "S108", # use of /tmp "S603", # subprocess.run security "S607", # subprocess.run with relative path "E501", # line too long "S112", # logging try/except/continue ] select = [ "E", "F", "W", # flake8 "C", # mccabe "I", # isort "N", # pep8-naming "D", # flake8-docstrings "ANN", # flake8-annotations "S", # flake8-bandit "BLE", # flake8-blind-except "B", # flake8-bugbear "A", # flake8-builtins "G", # flake8-logging-format "ERA", # eradicate "ISC", # flake8-implicit-str-concat "RUF", # Ruff-specific rules ] unfixable = [ "ERA", # Don't remove commented-out code ] [tool.ruff.lint.per-file-ignores] "tests/*" = ["S101"] [tool.ruff.lint.mccabe] max-complexity = 10 [tool.ruff.lint.isort] known-first-party = ["ai_marketplace_monitor"] [tool.ruff.lint.pydocstyle] convention = "google" [tool.isort] multi_line_output = 3 include_trailing_comma = true force_grid_wrap = 0 use_parentheses = true line_length = 99 known_third_party = ["invoke", "nox"] [tool.black] line-length = 99 target-version = ["py39"] [tool.mypy] warn_return_any = false warn_unused_configs = true [[tool.mypy.overrides]] module = ["pytest.*", "invoke.*", "nox.*"] allow_redefinition = false check_untyped_defs = true ignore_errors = false ignore_missing_imports = true implicit_reexport = true local_partial_types = true strict_optional = true strict_equality = true no_implicit_optional = true warn_unused_ignores = true warn_unreachable = true warn_no_return = true [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [dependency-groups] dev = ["pytest-asyncio>=1.1.0"] test = ["pytest-asyncio>=1.1.0"]