Downstream packaging¶
This page is for distribution packagers building click-extra from source, either a PyPI sdist or a Git tag. To install it on your own system, use uv pip install click-extra or your distribution’s package.
Dependencies¶
This is a graph of the Python package’s dependencies. Boxes hold the dependencies it declares directly, drawn as hexagons: one box for the primary set, and one for each extra. Transitive dependencies render outside the boxes, as ovals:
flowchart LR
click_extra[["`click-extra`"]]
subgraph primary-deps [Primary dependencies]
extra_platforms{{"`extra-platforms`"}}
cloup{{"`cloup`"}}
tabulate{{"`tabulate`"}}
wcmatch{{"`wcmatch`"}}
click_0{{"`click`"}}
wcwidth{{"`wcwidth`"}}
end
requests(["`requests`"])
jinja2(["`jinja2`"])
mkdocs_get_deps(["`mkdocs-get-deps`"])
colorama(["`colorama`"])
markdown_it_py(["`markdown-it-py`"])
python_dateutil(["`python-dateutil`"])
ghp_import(["`ghp-import`"])
markdown(["`markdown`"])
markupsafe(["`markupsafe`"])
mdit_py_plugins(["`mdit-py-plugins`"])
mergedeep(["`mergedeep`"])
pyyaml_env_tag(["`pyyaml-env-tag`"])
typing_extensions(["`typing-extensions`"])
alabaster(["`alabaster`"])
babel(["`babel`"])
bracex(["`bracex`"])
certifi(["`certifi`"])
charset_normalizer(["`charset-normalizer`"])
idna(["`idna`"])
imagesize(["`imagesize`"])
iniconfig(["`iniconfig`"])
mdurl(["`mdurl`"])
pathspec(["`pathspec`"])
platformdirs(["`platformdirs`"])
pluggy(["`pluggy`"])
roman_numerals(["`roman-numerals`"])
six(["`six`"])
snowballstemmer(["`snowballstemmer`"])
sphinxcontrib_applehelp(["`sphinxcontrib-applehelp`"])
sphinxcontrib_devhelp(["`sphinxcontrib-devhelp`"])
sphinxcontrib_htmlhelp(["`sphinxcontrib-htmlhelp`"])
sphinxcontrib_jsmath(["`sphinxcontrib-jsmath`"])
sphinxcontrib_qthelp(["`sphinxcontrib-qthelp`"])
sphinxcontrib_serializinghtml(["`sphinxcontrib-serializinghtml`"])
tzdata(["`tzdata`"])
urllib3(["`urllib3`"])
watchdog(["`watchdog`"])
subgraph ext_carapace [--extra carapace]
pyyaml{{"`pyyaml >=6.0.3`"}}
end
subgraph ext_hjson [--extra hjson]
hjson{{"`hjson >=3.1`"}}
end
subgraph ext_json5 [--extra json5]
json5{{"`json5 >=0.12.1`"}}
end
subgraph ext_mkdocs [--extra mkdocs]
mkdocs{{"`mkdocs >=1.4`"}}
pymdown_extensions{{"`pymdown-extensions >=10`"}}
ext_mkdocs_pygments{{"`pygments >=2.14`"}}
end
subgraph ext_pygments [--extra pygments]
ext_pygments_pygments{{"`pygments >=2.14`"}}
end
subgraph ext_pytest [--extra pytest]
pytest{{"`pytest >=9`"}}
end
subgraph ext_sphinx [--extra sphinx]
sphinx{{"`sphinx >=8`"}}
myst_parser{{"`myst-parser >=5.1`"}}
packaging{{"`packaging >=23`"}}
docutils{{"`docutils >=0.20`"}}
pygments{{"`pygments >=2.18`"}}
end
subgraph ext_toml [--extra toml]
tomlrt{{"`tomlrt >=2.2.10`"}}
end
subgraph ext_yaml [--extra yaml]
ext_yaml_pyyaml{{"`pyyaml >=6.0.3`"}}
end
click_extra ==>|" >=8.5.1 "| click_0
click_extra ==>|" >=4 "| cloup
click_extra ==>|" >=14 "| extra_platforms
click_extra ==>|" >=0.10 "| tabulate
click_extra ==>|" >=10 "| wcmatch
click_extra ==>|" >=0.8.3 "| wcwidth
sphinx --> requests
sphinx --> jinja2
sphinx --> packaging
sphinx --> colorama
sphinx --> docutils
sphinx --> pygments
sphinx --> alabaster
sphinx --> babel
sphinx --> imagesize
sphinx --> roman_numerals
sphinx --> snowballstemmer
sphinx --> sphinxcontrib_applehelp
sphinx --> sphinxcontrib_devhelp
sphinx --> sphinxcontrib_htmlhelp
sphinx --> sphinxcontrib_jsmath
sphinx --> sphinxcontrib_qthelp
sphinx --> sphinxcontrib_serializinghtml
mkdocs --> pyyaml
mkdocs --> jinja2
mkdocs --> mkdocs_get_deps
mkdocs --> packaging
mkdocs --> click_0
mkdocs --> colorama
mkdocs --> ghp_import
mkdocs --> markdown
mkdocs --> markupsafe
mkdocs --> mergedeep
mkdocs --> pyyaml_env_tag
mkdocs --> pathspec
mkdocs --> watchdog
myst_parser --> sphinx
myst_parser --> pyyaml
myst_parser --> jinja2
myst_parser --> docutils
myst_parser --> markdown_it_py
myst_parser --> mdit_py_plugins
pytest --> packaging
pytest --> colorama
pytest --> pygments
pytest --> iniconfig
pytest --> pluggy
cloup --> click_0
cloup --> typing_extensions
pymdown_extensions --> pyyaml
pymdown_extensions --> markdown
extra_platforms --> pytest
tabulate --> wcwidth
tomlrt --> typing_extensions
wcmatch --> bracex
requests --> certifi
requests --> charset_normalizer
requests --> idna
requests --> urllib3
jinja2 --> markupsafe
mkdocs_get_deps --> pyyaml
mkdocs_get_deps --> mergedeep
mkdocs_get_deps --> platformdirs
markdown_it_py --> mdurl
ghp_import --> python_dateutil
mdit_py_plugins --> markdown_it_py
pyyaml_env_tag --> pyyaml
python_dateutil --> six
python_dateutil --> tzdata
click_extra -.-> ext_carapace
click_extra -.-> ext_hjson
click_extra -.-> ext_json5
click_extra -.-> ext_mkdocs
click_extra -.-> ext_pygments
click_extra -.-> ext_pytest
click_extra -.-> ext_sphinx
click_extra -.-> ext_toml
click_extra -.-> ext_yaml
ext_mkdocs_pygments -.- pygments
ext_pygments_pygments -.- pygments
ext_yaml_pyyaml -.- pyyaml
click alabaster "https://pypi.org/project/alabaster/" _blank
click babel "https://pypi.org/project/babel/" _blank
click bracex "https://pypi.org/project/bracex/" _blank
click certifi "https://pypi.org/project/certifi/" _blank
click charset_normalizer "https://pypi.org/project/charset-normalizer/" _blank
click click_0 "https://pypi.org/project/click/" _blank
click click_extra "https://pypi.org/project/click-extra/" _blank
click cloup "https://pypi.org/project/cloup/" _blank
click colorama "https://pypi.org/project/colorama/" _blank
click docutils "https://pypi.org/project/docutils/" _blank
click extra_platforms "https://pypi.org/project/extra-platforms/" _blank
click ghp_import "https://pypi.org/project/ghp-import/" _blank
click hjson "https://pypi.org/project/hjson/" _blank
click idna "https://pypi.org/project/idna/" _blank
click imagesize "https://pypi.org/project/imagesize/" _blank
click iniconfig "https://pypi.org/project/iniconfig/" _blank
click jinja2 "https://pypi.org/project/jinja2/" _blank
click json5 "https://pypi.org/project/json5/" _blank
click markdown "https://pypi.org/project/markdown/" _blank
click markdown_it_py "https://pypi.org/project/markdown-it-py/" _blank
click markupsafe "https://pypi.org/project/markupsafe/" _blank
click mdit_py_plugins "https://pypi.org/project/mdit-py-plugins/" _blank
click mdurl "https://pypi.org/project/mdurl/" _blank
click mergedeep "https://pypi.org/project/mergedeep/" _blank
click mkdocs "https://pypi.org/project/mkdocs/" _blank
click mkdocs_get_deps "https://pypi.org/project/mkdocs-get-deps/" _blank
click myst_parser "https://pypi.org/project/myst-parser/" _blank
click packaging "https://pypi.org/project/packaging/" _blank
click pathspec "https://pypi.org/project/pathspec/" _blank
click platformdirs "https://pypi.org/project/platformdirs/" _blank
click pluggy "https://pypi.org/project/pluggy/" _blank
click pygments "https://pypi.org/project/pygments/" _blank
click pymdown_extensions "https://pypi.org/project/pymdown-extensions/" _blank
click pytest "https://pypi.org/project/pytest/" _blank
click python_dateutil "https://pypi.org/project/python-dateutil/" _blank
click pyyaml "https://pypi.org/project/pyyaml/" _blank
click pyyaml_env_tag "https://pypi.org/project/pyyaml-env-tag/" _blank
click requests "https://pypi.org/project/requests/" _blank
click roman_numerals "https://pypi.org/project/roman-numerals/" _blank
click six "https://pypi.org/project/six/" _blank
click snowballstemmer "https://pypi.org/project/snowballstemmer/" _blank
click sphinx "https://pypi.org/project/sphinx/" _blank
click sphinxcontrib_applehelp "https://pypi.org/project/sphinxcontrib-applehelp/" _blank
click sphinxcontrib_devhelp "https://pypi.org/project/sphinxcontrib-devhelp/" _blank
click sphinxcontrib_htmlhelp "https://pypi.org/project/sphinxcontrib-htmlhelp/" _blank
click sphinxcontrib_jsmath "https://pypi.org/project/sphinxcontrib-jsmath/" _blank
click sphinxcontrib_qthelp "https://pypi.org/project/sphinxcontrib-qthelp/" _blank
click sphinxcontrib_serializinghtml "https://pypi.org/project/sphinxcontrib-serializinghtml/" _blank
click tabulate "https://pypi.org/project/tabulate/" _blank
click tomlrt "https://pypi.org/project/tomlrt/" _blank
click typing_extensions "https://pypi.org/project/typing-extensions/" _blank
click tzdata "https://pypi.org/project/tzdata/" _blank
click urllib3 "https://pypi.org/project/urllib3/" _blank
click watchdog "https://pypi.org/project/watchdog/" _blank
click wcmatch "https://pypi.org/project/wcmatch/" _blank
click wcwidth "https://pypi.org/project/wcwidth/" _blank
click ext_mkdocs_pygments "https://pypi.org/project/pygments/" _blank
click ext_pygments_pygments "https://pypi.org/project/pygments/" _blank
click ext_yaml_pyyaml "https://pypi.org/project/pyyaml/" _blank
style click_extra stroke-width:3px
style click_0 stroke-width:3px
style cloup stroke-width:3px
style docutils stroke-width:3px
style extra_platforms stroke-width:3px
style hjson stroke-width:3px
style json5 stroke-width:3px
style mkdocs stroke-width:3px
style myst_parser stroke-width:3px
style packaging stroke-width:3px
style pygments stroke-width:3px
style pymdown_extensions stroke-width:3px
style pytest stroke-width:3px
style pyyaml stroke-width:3px
style sphinx stroke-width:3px
style tabulate stroke-width:3px
style tomlrt stroke-width:3px
style wcmatch stroke-width:3px
style wcwidth stroke-width:3px
style ext_mkdocs_pygments stroke-width:3px,stroke-dasharray:5 5
style ext_pygments_pygments stroke-width:3px,stroke-dasharray:5 5
style ext_yaml_pyyaml stroke-width:3px,stroke-dasharray:5 5
style primary-deps fill:#1565C020,stroke:#42A5F5
style ext_carapace fill:#7B1FA220,stroke:#BA68C8
style ext_hjson fill:#7B1FA220,stroke:#BA68C8
style ext_json5 fill:#7B1FA220,stroke:#BA68C8
style ext_mkdocs fill:#7B1FA220,stroke:#BA68C8
style ext_pygments fill:#7B1FA220,stroke:#BA68C8
style ext_pytest fill:#7B1FA220,stroke:#BA68C8
style ext_sphinx fill:#7B1FA220,stroke:#BA68C8
style ext_toml fill:#7B1FA220,stroke:#BA68C8
style ext_yaml fill:#7B1FA220,stroke:#BA68C8
Building¶
The wheel is built with uv_build, declared as the [build-system] backend. Distributions that do not yet package uv-build can fall back to setuptools. The [tool.setuptools] table is a compatibility shim for that case: it declares click_extra’s py.typed marker as package-data so a setuptools.build_meta build ships it, which setuptools otherwise drops when it installs only *.py. uv_build ignores the table entirely.
Test suite¶
Since click-extra 8.6.1, the PyPI sdist ships tests/, docs/ and the .github/ files the tests read, so the suite runs straight from the sdist. Earlier releases shipped no tests; those builds must start from a Git tag tarball instead.
The suite is friendly to a hermetic build sandbox:
Network tests are marked. Exclude them with
-m "not network": the build sandbox has no outbound network.The local HTTP server binds an address, not a name. The configuration tests serving a config file over HTTP run against
pytest-httpserver, whosehttpserver_listen_addressfixturetests/conftest.pypins to127.0.0.1. Itslocalhostdefault would need a resolver, which a sandbox is entitled to deny: on macOS the Nix one does, and every such test then errored withsocket.gaierror. Whether your sandbox also gates the loopback socket itself is a separate question, and may still call for an exemption.Configuration-discovery tests are
HOME-independent. Therunnerfixture pinsHOME(and its platform equivalents) to an isolated directory, so the handful of tests asserting on the config-search debug output stay deterministic even whereHOME=/homeless-shelter(Guix, Nixpkgs).The MkDocs tests self-skip when their extras are missing.
tests/mkdocs/needs the MkDocs documentation extras (mkdocs,mkdocs-click,pymdown-extensions);tests/mkdocs/conftest.pyskips the whole tree throughcollect_ignore_globwhen any of them is absent, so no--ignore=tests/mkdocsis needed.The Sphinx tests self-skip too, when
sphinxormyst-parseris absent, the few outsidetests/sphinx/included, and so doestests/sphinx/test_sphinx_matrix.pywhen nogitbinary is onPATH. That module is the only one needing a command rather than an import: it walks the tags of throwaway repositories it builds withgit init. Addinggitto the build inputs runs the tests of that module; leaving it out costs only those.
So a hermetic builder needs one flag, to leave the network tests out:
$ pytest -m "not network"
Run it against the package you just built, not the one the system already carries. [tool.pytest] addopts sets --import-mode=importlib, and the pytest console script puts no working directory on sys.path, so a bare pytest in the source tree imports click_extra from the system site-packages: the tests then check the installed version, or fail to collect when the two disagree. Install the wheel into a virtual environment and call that environment’s interpreter:
$ python -m venv --system-site-packages test-env
$ test-env/bin/python -m installer dist/*.whl
$ test-env/bin/python -m pytest -m "not network"
Several test modules import optional libraries at collection time (hjson, jsonschema, pygments and others) to exercise the matching features. Install them to run the full suite, as the project’s own CI does.
Test helpers for downstream projects¶
click_extra.pytest (installed with the [pytest] extra) provides fixtures reused by projects built on click-extra, notably the runner/invoke fixtures that pin HOME, and assert_output_regex. Platform-skip decorators such as @skip_hermetic_build come from extra-platforms.