# PACKAGING [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] dynamic = ["version"] name = "python-telegram-bot" description = "We have made you a wrapper you can't refuse" readme = "README.rst" requires-python = ">=3.10" license = "LGPL-3.0-only" license-files = ["LICENSE", "LICENSE.dual", "LICENSE.lesser"] authors = [ { name = "Leandro Toledo", email = "devs@python-telegram-bot.org" } ] keywords = [ "python", "telegram", "bot", "api", "wrapper", ] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Communications :: Chat", "Topic :: Internet", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", ] dependencies = [ "httpx >=0.27,<0.29", "httpcore >=1.0.9; python_version >= '3.14'" # httpx doesn't pin this as of 0.28.1 ] [project.urls] "Homepage" = "https://python-telegram-bot.org" "Documentation" = "https://docs.python-telegram-bot.org" "Bug Tracker" = "https://github.com/python-telegram-bot/python-telegram-bot/issues" "Source Code" = "https://github.com/python-telegram-bot/python-telegram-bot" "News" = "https://t.me/pythontelegrambotchannel" "Changelog" = "https://docs.python-telegram-bot.org/en/stable/changelog.html" "Support" = "https://t.me/pythontelegrambotgroup" [project.optional-dependencies] # Make sure to install those as additional_dependencies in the pre-commit hooks # # When dependencies release new versions and tests succeed, we should try to expand the allowed # versions and only increase the lower bound if necessary # # When adding new extras, make sure to update `ext` and `all` accordingly # Optional dependencies for production all = [ "python-telegram-bot[ext,http2,passport,socks]", ] callback-data = [ # Cachetools doesn't have a strict stability policy. Let's be cautious for now. "cachetools>=7.0.0,<8.0.0", ] ext = [ "python-telegram-bot[callback-data,job-queue,rate-limiter,webhooks]", ] http2 = [ "httpx[http2]", ] job-queue = [ # APS doesn't have a strict stability policy. Let's be cautious for now. "APScheduler>=3.10.4,<3.12.0", ] passport = [ "cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1", # cffi is a dependency of cryptography and added support for python 3.13 in 1.17.0rc1 "cffi >= 1.17.0rc1; python_version > '3.12'" ] rate-limiter = [ "aiolimiter>=1.1,<1.3", ] socks = [ "httpx[socks]", ] webhooks = [ # tornado is rather stable, but let's not allow the next major release without prior testing "tornado~=6.5", ] [dependency-groups] tests = [ # required for building the wheels for releases "build", # For the test suite "pytest==9.0.3", # needed because pytest doesn't come with native support for coroutines as tests "pytest-asyncio==0.21.2", # xdist runs tests in parallel "pytest-xdist==3.8.0", # Used for flaky tests (flaky decorator) "flaky>=3.8.1", # used in test_official for parsing tg docs "beautifulsoup4", # For testing with timezones. Might not be needed on all systems, but to ensure that unit tests # run correctly on all systems, we include it here. "tzdata", # We've deprecated support pytz, but we still need it for testing that it works with the library. "pytz", # Install coverage: "pytest-cov" ] docs = [ "chango~=0.6.0; python_version >= '3.12'", "sphinx==9.1.0; python_version >= '3.12'", "furo==2025.12.19", "sphinx-paramlinks==0.6.0", "sphinxcontrib-mermaid==2.0.2", "sphinx-copybutton==0.5.2", "sphinx-inline-tabs==2025.12.21.14", # Temporary. See #4387 "sphinx-build-compatibility @ git+https://github.com/readthedocs/sphinx-build-compatibility.git@58aabc5f207c6c2421f23d3578adc0b14af57047", # For python 3.14 support, we need a version of pydantic-core >= 2.35.0, since it upgrades the # rust toolchain, required for building the project. # This should ideally be done in `chango`'s dependencies. We can remove this once a new # stable pydantic version is released. "pydantic >= 2.12.0a1 ; python_version >= '3.14'" ] linting = [ "prek", "ruff==0.15.16", "mypy==1.20.2", "pylint==4.0.5" ] all = [{ include-group = "tests" }, { include-group = "docs" }, { include-group = "linting"}] # HATCH [tool.hatch.version] # dynamically evaluates the `__version__` variable in that file source = "code" path = "src/telegram/_version.py" # See also https://github.com/pypa/hatch/issues/1230 for discussion # the source distribution will include most of the files in the root directory [tool.hatch.build.targets.sdist] exclude = [".venv*", "venv*", ".github", "uv.lock"] # the wheel will only include the src/telegram package [tool.hatch.build.targets.wheel] packages = ["src/telegram"] # uv [tool.uv] exclude-newer = "7 days" # CHANGO [tool.chango] sys_path = "changes" chango_instance = { name= "chango_instance", module = "config" } # RUFF: [tool.ruff] line-length = 99 show-fixes = true [tool.ruff.lint] typing-extensions = false ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PERF203", "ASYNC240"] select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE", "G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR", "RUF022", "RUF023", "Q", "INP", "W", "YTT", "DTZ", "ARG", "T20", "FURB", "DOC", "TRY", "D100", "D101", "D102", "D103", "D300", "D418", "D419", "S"] # Add "A (flake8-builtins)" after we drop pylint [tool.ruff.lint.per-file-ignores] "tests/*.py" = ["B018"] "tests/**.py" = ["RUF012", "ASYNC230", "DTZ", "ARG", "T201", "ASYNC109", "D", "S", "TRY"] "src/telegram/**.py" = ["TRY003"] "src/telegram/ext/_applicationbuilder.py" = ["TRY004"] "src/telegram/ext/filters.py" = ["D102"] "docs/**.py" = ["INP001", "ARG", "D", "TRY003", "S"] "examples/**.py" = ["ARG", "D", "S105", "TRY003"] [tool.ruff.lint.pydocstyle] convention = "google" # PYLINT: [tool.pylint."messages control"] enable = ["useless-suppression"] disable = ["duplicate-code", "too-many-arguments", "too-many-public-methods", "too-few-public-methods", "broad-exception-caught", "too-many-instance-attributes", "fixme", "missing-function-docstring", "missing-class-docstring", "too-many-locals", "too-many-lines", "too-many-branches", "too-many-statements", "cyclic-import", "too-many-positional-arguments", ] [tool.pylint.main] # run pylint across multiple cpu cores to speed it up- # https://pylint.pycqa.org/en/latest/user_guide/run.html?#parallel-execution to know more jobs = 0 py-version = "3.10" [tool.pylint.classes] exclude-protected = ["_unfrozen"] # PYTEST: [tool.pytest.ini_options] testpaths = ["tests"] pythonpath = ["src"] addopts = "--no-success-flaky-report -rX" filterwarnings = [ "error", "ignore::DeprecationWarning", 'ignore:Tasks created via `Application\.create_task` while the application is not running', "ignore::ResourceWarning", # TODO: Write so good code that we don't need to ignore ResourceWarnings anymore # Unfortunately due to https://github.com/pytest-dev/pytest/issues/8343 we can't have this here # and instead do a trick directly in tests/conftest.py # ignore::telegram.utils.deprecate.TelegramDeprecationWarning ] markers = [ "dev", # If you want to test a specific test, use this "no_req", "req", ] asyncio_mode = "auto" log_cli_format = "%(funcName)s - Line %(lineno)d - %(message)s" # log_cli_level = "DEBUG" # uncomment to see DEBUG logs # MYPY: [tool.mypy] mypy_path = "src" warn_unused_ignores = true warn_unused_configs = true disallow_untyped_defs = true disallow_incomplete_defs = true disallow_untyped_decorators = true show_error_codes = true python_version = "3.10" # For some files, it's easier to just disable strict-optional all together instead of # cluttering the code with `# type: ignore`s or stuff like # `if self.text is None: raise RuntimeError()` [[tool.mypy.overrides]] module = [ "telegram._callbackquery", "telegram._file", "telegram._message", "telegram._files.file" ] strict_optional = false # type hinting for asyncio in webhookhandler is a bit tricky because it depends on the OS [[tool.mypy.overrides]] module = "telegram.ext._utils.webhookhandler" warn_unused_ignores = false # The libs listed below are only used for the `customwebhookbot_*.py` examples # let's just ignore type checking for them for now [[tool.mypy.overrides]] module = [ "flask.*", "quart.*", "starlette.*", "uvicorn.*", "asgiref.*", "django.*", "apscheduler.*", # not part of `customwebhookbot_*.py` examples ] ignore_missing_imports = true # COVERAGE: [tool.coverage.run] branch = true source = ["src/telegram"] parallel = true concurrency = ["thread", "multiprocessing"] omit = [ "tests/", "src/telegram/__main__.py" ] [tool.coverage.report] exclude_also = [ "@overload", "@abstractmethod", "if TYPE_CHECKING:" ]