[project] name = "mitmproxy" description = "An interactive, SSL/TLS-capable intercepting proxy for HTTP/1, HTTP/2, and WebSockets." readme = "README.md" requires-python = ">=3.12" license = {file="LICENSE"} authors = [{name = "Aldo Cortesi", email = "aldo@corte.si"}] maintainers = [{name = "Maximilian Hils", email = "mitmproxy@maximilianhils.com"}] dynamic = ["version"] classifiers = [ "License :: OSI Approved :: MIT License", "Development Status :: 5 - Production/Stable", "Environment :: Console :: Curses", "Operating System :: MacOS", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Security", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: Proxy Servers", "Topic :: System :: Networking :: Monitoring", "Topic :: Software Development :: Testing", "Typing :: Typed", ] # https://packaging.python.org/en/latest/discussions/install-requires-vs-requirements/#install-requires # It is not considered best practice to use install_requires to pin dependencies to specific versions. dependencies = [ "aioquic>=1.2.0,<=1.2.0", "argon2-cffi>=23.1.0,<=25.1.0", "asgiref>=3.2.10,<=3.12.1", "backports.zstd>=1.7.0,<=1.7.0 ; python_version<'3.14'", "bcrypt>=5.0.0,<=5.0.0", "Brotli>=1.0,<=1.2.0", "certifi>=2019.9.11", # no upper bound here to get latest CA bundle "cryptography>=42.0,<=50.0.0", # relaxed upper bound here to get security fixes "flask>=3.0,<=3.1.3", "h11>=0.16.0,<=0.16.0", "h2>=4.3.0,<=4.4.1", "hyperframe>=6.0,<=6.1.0", "kaitaistruct>=0.10,<=0.11", "ldap3>=2.8,<=2.9.1", "mitmproxy_rs>=0.12.6,<0.13", # relaxed upper bound here: we control this "pydivert>=2.0.3,<=3.1.3; sys_platform == 'win32'", "pyOpenSSL>=24.3,<=27.0.0", "pyparsing>=3.3.2,<=3.3.2", "pyperclip>=1.9.0,<=1.11.0", "ruamel.yaml>=0.18.10,<=0.19.1", "sortedcontainers>=2.3,<=2.4.0", "tornado>=6.5.0,<=6.5.8", "typing-extensions>=4.13.2,<=4.14; python_version < '3.13'", "urwid>=2.6.14,<=4.0.9", "wsproto>=1.0,<=1.3.2", "publicsuffix2>=2.20190812,<=2.20191221", ] [dependency-groups] dev = [ "click==8.4.2", "hypothesis==6.130.6", "maturin==1.14.1", "pdoc==16.0.0", "pyinstaller==6.22.0", "pyinstaller-hooks-contrib==2026.6", "pytest-asyncio==1.2.0", "pytest-cov==7.0.0", "pytest-timeout==2.4.0", "pytest-xdist==3.8.0", "pytest==8.4.2", "requests==2.34.2", "wheel==0.48.0", "build==1.5.0", "mypy==1.20.2", "types-requests==2.33.0.20260408", {include-group = "tox"}, {include-group = "ruff"}, ] tox = [ "tox==4.55.1", "tox-uv==1.35.2", ] ruff = [ "ruff==0.16.3", ] deploy = [ "awscli==1.46.0", "twine==7.0.0", ] [project.urls] Homepage = "https://mitmproxy.org" Source = "https://github.com/mitmproxy/mitmproxy/" Documentation = "https://docs.mitmproxy.org/stable/" Issues = "https://github.com/mitmproxy/mitmproxy/issues" [project.scripts] mitmproxy = "mitmproxy.tools.main:mitmproxy" mitmdump = "mitmproxy.tools.main:mitmdump" mitmweb = "mitmproxy.tools.main:mitmweb" [project.entry-points.pyinstaller40] hook-dirs = "mitmproxy.utils.pyinstaller:hook_dirs" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.setuptools.dynamic] version = {attr = "mitmproxy.version.VERSION"} [tool.setuptools.packages.find] include = ["mitmproxy*"] [tool.coverage.run] branch = false omit = [ "*contrib*", "*tnetstring*", "*platform*", "*main.py", ] [tool.coverage.report] show_missing = true exclude_lines = [ "pragma: no cover", "raise NotImplementedError", "raise AssertionError", "if typing.TYPE_CHECKING:", "if TYPE_CHECKING:", "@overload", "@abstractmethod", "assert_never", "\\.\\.\\.", ] [tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" testpaths = "test" addopts = "--capture=no --color=yes" filterwarnings = [ "ignore::DeprecationWarning:tornado.*:", "ignore:datetime.datetime.utcnow:DeprecationWarning:aioquic.*:", "error::RuntimeWarning", "error::pytest.PytestUnraisableExceptionWarning", ] [tool.pytest.individual_coverage] exclude = [ "mitmproxy/addons/__init__.py", "mitmproxy/addons/onboarding.py", "mitmproxy/addons/onboardingapp/__init__.py", "mitmproxy/contentviews/__init__.py", "mitmproxy/contentviews/base.py", "mitmproxy/contentviews/grpc.py", "mitmproxy/contrib/*", "mitmproxy/ctx.py", "mitmproxy/exceptions.py", "mitmproxy/flow.py", "mitmproxy/io/io.py", "mitmproxy/io/tnetstring.py", "mitmproxy/log.py", "mitmproxy/master.py", "mitmproxy/net/check.py", "mitmproxy/net/http/cookies.py", "mitmproxy/net/http/multipart.py", "mitmproxy/net/tls.py", "mitmproxy/platform/__init__.py", "mitmproxy/platform/linux.py", "mitmproxy/platform/openbsd.py", "mitmproxy/platform/osx.py", "mitmproxy/platform/pf.py", "mitmproxy/platform/windows.py", "mitmproxy/proxy/__init__.py", "mitmproxy/proxy/layers/http/__init__.py", "mitmproxy/proxy/layers/http/_base.py", "mitmproxy/proxy/layers/http/_events.py", "mitmproxy/proxy/layers/http/_hooks.py", "mitmproxy/proxy/layers/http/_http1.py", "mitmproxy/proxy/layers/http/_http2.py", "mitmproxy/proxy/layers/http/_http3.py", "mitmproxy/proxy/layers/http/_http_h2.py", "mitmproxy/proxy/layers/http/_http_h3.py", "mitmproxy/proxy/layers/http/_upstream_proxy.py", "mitmproxy/proxy/layers/tls.py", "mitmproxy/proxy/server.py", "mitmproxy/test/taddons.py", "mitmproxy/test/tflow.py", "mitmproxy/test/tutils.py", "mitmproxy/tools/console/commander/commander.py", "mitmproxy/tools/console/commandexecutor.py", "mitmproxy/tools/console/commands.py", "mitmproxy/tools/console/common.py", "mitmproxy/tools/console/consoleaddons.py", "mitmproxy/tools/console/eventlog.py", "mitmproxy/tools/console/flowdetailview.py", "mitmproxy/tools/console/flowlist.py", "mitmproxy/tools/console/flowview.py", "mitmproxy/tools/console/grideditor/base.py", "mitmproxy/tools/console/grideditor/col_bytes.py", "mitmproxy/tools/console/grideditor/col_subgrid.py", "mitmproxy/tools/console/grideditor/col_text.py", "mitmproxy/tools/console/grideditor/col_viewany.py", "mitmproxy/tools/console/grideditor/editors.py", "mitmproxy/tools/console/help.py", "mitmproxy/tools/console/keybindings.py", "mitmproxy/tools/console/keymap.py", "mitmproxy/tools/console/layoutwidget.py", "mitmproxy/tools/console/master.py", "mitmproxy/tools/console/options.py", "mitmproxy/tools/console/overlay.py", "mitmproxy/tools/console/quickhelp.py", "mitmproxy/tools/console/searchable.py", "mitmproxy/tools/console/signals.py", "mitmproxy/tools/console/statusbar.py", "mitmproxy/tools/console/tabs.py", "mitmproxy/tools/console/window.py", "mitmproxy/tools/main.py", "mitmproxy/tools/web/app.py", "mitmproxy/tools/web/master.py", "mitmproxy/tools/web/webaddons.py", "mitmproxy/utils/pyinstaller/*", "mitmproxy/utils/vt_codes.py", ] [tool.mypy] check_untyped_defs = true ignore_missing_imports = true files = [ "mitmproxy", "examples/addons", "release/*.py", ] exclude = [ "^docs/", "^release/build/", "^examples/contrib/", ] [[tool.mypy.overrides]] module = "mitmproxy.contrib.*" ignore_errors = true [[tool.mypy.overrides]] module = "tornado.*" ignore_errors = true [[tool.mypy.overrides]] module = "test.*" ignore_errors = true [tool.ruff] extend-exclude = ["mitmproxy/contrib/"] [tool.ruff.lint] select = ["E", "F", "I", "TID251"] ignore = ["F541", "E501"] [tool.ruff.lint.per-file-ignores] "examples/**" = ["TID251"] "test/**" = ["TID251"] [tool.ruff.lint.flake8-tidy-imports.banned-api] "asyncio.create_task".msg = "Use mitmproxy.utils.asyncio_utils.create_task instead to avoid GC footgun." [tool.ruff.lint.isort] # these rules are a bit weird, but they mimic our existing reorder_python_imports style. # if we break compatibility here, consider removing all customization + enforce absolute imports. force-single-line = true order-by-type = false section-order = ["future", "standard-library", "third-party", "local-folder","first-party"] no-lines-before = ["first-party"] known-first-party = ["test", "mitmproxy", "mitmproxy_rs"] [tool.tox] env_list = ["lint", "mypy", "py"] [tool.tox.env_run_base] runner = "uv-venv-lock-runner" package = "editable" dependency_groups = ["dev"] commands = [ ["mitmdump", "--version"], ["pytest", "-vv", "--cov-report", "xml", "--continue-on-collection-errors", "--cov=mitmproxy", "--cov=release", { replace = "posargs", default = ["--timeout", "60"], extend = true } ], ] [tool.tox.env.test-offline] commands = [["bash", "test/run-tests-offline.sh"]] allowlist_externals = ["bash"] [tool.tox.env.lint] commands = [["ruff", "check", "."]] dependency_groups = ["ruff"] [tool.tox.env.filename_matching] commands = [["python", "./test/filename_matching.py"]] dependency_groups = [] [tool.tox.env.mypy] commands = [["mypy"]] [tool.tox.env.individual_coverage] commands = [["python", "./test/individual_coverage.py", { default = [], replace = "posargs", extend = true }]] [tool.tox.env.old-dependencies] uv_resolution = "lowest-direct" runner = "uv-venv-runner" [tool.tox.env.fix] commands = [ ["ruff", "check", "--fix-only", "."], ["ruff", "format", "."], ] dependency_groups = ["ruff"]