Packaging

Distribution and packaging reference for repomatic, aimed at downstream packagers.

Dependencies

This is a graph of the Python package’s dependencies. Boxes hold the directly-declared dependencies (main set and each development group), drawn as hexagons; transitive dependencies render outside the boxes as ovals:

        flowchart LR
    repomatic[["`repomatic`"]]

    subgraph primary-deps [Primary dependencies]
        click_extra{{"`click-extra`"}}
        vt_py{{"`vt-py`"}}
        arrow{{"`arrow`"}}
        wcmatch{{"`wcmatch`"}}
        py_walk{{"`py-walk`"}}
        pyproject_metadata{{"`pyproject-metadata`"}}
        tomlrt{{"`tomlrt`"}}
        packaging{{"`packaging`"}}
        pyyaml{{"`pyyaml`"}}
        boltons{{"`boltons`"}}
        extra_platforms{{"`extra-platforms`"}}
        backports_strenum{{"`backports-strenum`"}}
        pyelftools{{"`pyelftools`"}}
    end

    aiohttp(["`aiohttp`"])
    typing_extensions(["`typing-extensions`"])
    pygments(["`pygments`"])
    requests(["`requests`"])
    jinja2(["`jinja2`"])
    yarl(["`yarl`"])
    aiosignal(["`aiosignal`"])
    beautifulsoup4(["`beautifulsoup4`"])
    click_0(["`click`"])
    cloup(["`cloup`"])
    colorama(["`colorama`"])
    docutils(["`docutils`"])
    markdown_it_py(["`markdown-it-py`"])
    multidict(["`multidict`"])
    tomli(["`tomli`"])
    accessible_pygments(["`accessible-pygments`"])
    exceptiongroup(["`exceptiongroup`"])
    frozenlist(["`frozenlist`"])
    idna(["`idna`"])
    mdit_py_plugins(["`mdit-py-plugins`"])
    pluggy(["`pluggy`"])
    propcache(["`propcache`"])
    python_dateutil(["`python-dateutil`"])
    sphinx_basic_ng(["`sphinx-basic-ng`"])
    tabulate(["`tabulate`"])
    wcwidth(["`wcwidth`"])
    aiofiles(["`aiofiles`"])
    aiohappyeyeballs(["`aiohappyeyeballs`"])
    alabaster(["`alabaster`"])
    async_timeout(["`async-timeout`"])
    attrs(["`attrs`"])
    babel(["`babel`"])
    bracex(["`bracex`"])
    certifi(["`certifi`"])
    charset_normalizer(["`charset-normalizer`"])
    deepmerge(["`deepmerge`"])
    execnet(["`execnet`"])
    imagesize(["`imagesize`"])
    iniconfig(["`iniconfig`"])
    markupsafe(["`markupsafe`"])
    mdurl(["`mdurl`"])
    psutil(["`psutil`"])
    roman_numerals(["`roman-numerals`"])
    six(["`six`"])
    sly(["`sly`"])
    snowballstemmer(["`snowballstemmer`"])
    soupsieve(["`soupsieve`"])
    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`"])

    subgraph grp_docs [--group docs]
        sphinx{{"`sphinx >=8`"}}
        myst_parser{{"`myst-parser >=5.1`"}}
        furo{{"`furo >=2025.9.25`"}}
        sphinx_datatables{{"`sphinx-datatables >=1`"}}
        sphinxcontrib_mermaid{{"`sphinxcontrib-mermaid >=1.2.3`"}}
        sphinxcontrib_jquery{{"`sphinxcontrib-jquery >=4`"}}
        sphinx_autodoc_typehints{{"`sphinx-autodoc-typehints >=2.4`"}}
        sphinx_copybutton{{"`sphinx-copybutton >=0.5.2`"}}
        sphinx_design{{"`sphinx-design >=0.6`"}}
        sphinxext_opengraph{{"`sphinxext-opengraph >=0.13`"}}
    end

    subgraph grp_test [--group test]
        pytest{{"`pytest >=9`"}}
        pytest_cov{{"`pytest-cov >=4`"}}
        pytest_xdist{{"`pytest-xdist >=3.7`"}}
        coverage{{"`coverage >=7.11`"}}
        pytest_github_actions_annotate_failures{{"`pytest-github-actions-annotate-failures >=0.2`"}}
        pytest_randomly{{"`pytest-randomly >=3`"}}
    end

    subgraph grp_typing [--group typing]
        types_boltons{{"`types-boltons >=25.0.0.20250822`"}}
        types_docutils{{"`types-docutils >=0.22.3.20251115`"}}
        types_pyyaml{{"`types-pyyaml >=6.0.12.9`"}}
    end

    repomatic ==>|" >=8.8 "| click_extra
    repomatic ==>|" >=17 "| packaging
    repomatic ==>|" >=1.3 "| arrow
    repomatic ==>|" >=6.0.3 "| pyyaml
    repomatic ==>|" >=0.18 "| vt_py
    repomatic ==>|" >=10 "| wcmatch
    repomatic ==>|" >=25 "| boltons
    repomatic ==>|" >=12.0.2 "| extra_platforms
    repomatic ==>|" >=0.3.1 "| py_walk
    repomatic ==>|" >=0.9 "| pyproject_metadata
    repomatic ==>|" >=1.7.6 "| tomlrt
    repomatic ==>|" >=1 "| backports_strenum
    repomatic ==>|" >=0.33 "| pyelftools
    sphinx --> packaging
    sphinx --> pygments
    sphinx --> requests
    sphinx --> jinja2
    sphinx --> colorama
    sphinx --> docutils
    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
    click_extra --> sphinx
    click_extra --> pygments
    click_extra --> click_0
    click_extra --> cloup
    click_extra --> docutils
    click_extra --> tomli
    click_extra --> wcmatch
    click_extra --> boltons
    click_extra --> extra_platforms
    click_extra --> tabulate
    click_extra --> wcwidth
    click_extra --> deepmerge
    pytest --> packaging
    pytest --> pygments
    pytest --> colorama
    pytest --> tomli
    pytest --> exceptiongroup
    pytest --> pluggy
    pytest --> iniconfig
    myst_parser --> sphinx
    myst_parser --> jinja2
    myst_parser --> docutils
    myst_parser --> markdown_it_py
    myst_parser --> pyyaml
    myst_parser --> mdit_py_plugins
    furo --> sphinx
    furo --> pygments
    furo --> beautifulsoup4
    furo --> accessible_pygments
    furo --> sphinx_basic_ng
    pytest_cov --> pytest
    pytest_cov --> coverage
    pytest_cov --> pluggy
    pytest_xdist --> pytest
    pytest_xdist --> execnet
    pytest_xdist --> psutil
    sphinx_datatables --> sphinx
    sphinx_datatables --> packaging
    sphinx_datatables --> sphinxcontrib_jquery
    sphinxcontrib_mermaid --> sphinx
    sphinxcontrib_mermaid --> jinja2
    sphinxcontrib_mermaid --> pyyaml
    arrow --> python_dateutil
    arrow --> tzdata
    coverage --> tomli
    sphinxcontrib_jquery --> sphinx
    vt_py --> aiohttp
    vt_py --> aiofiles
    wcmatch --> bracex
    py_walk --> sly
    pyproject_metadata --> packaging
    pytest_github_actions_annotate_failures --> pytest
    pytest_randomly --> pytest
    sphinx_autodoc_typehints --> sphinx
    sphinx_copybutton --> sphinx
    sphinx_design --> sphinx
    sphinxext_opengraph --> sphinx
    tomlrt --> typing_extensions
    aiohttp --> typing_extensions
    aiohttp --> yarl
    aiohttp --> aiosignal
    aiohttp --> multidict
    aiohttp --> frozenlist
    aiohttp --> propcache
    aiohttp --> aiohappyeyeballs
    aiohttp --> async_timeout
    aiohttp --> attrs
    requests --> idna
    requests --> certifi
    requests --> charset_normalizer
    requests --> urllib3
    jinja2 --> markupsafe
    beautifulsoup4 --> typing_extensions
    beautifulsoup4 --> soupsieve
    click_0 --> colorama
    cloup --> typing_extensions
    cloup --> click_0
    markdown_it_py --> mdurl
    accessible_pygments --> pygments
    exceptiongroup --> typing_extensions
    mdit_py_plugins --> markdown_it_py
    python_dateutil --> six
    sphinx_basic_ng --> sphinx
    tabulate --> wcwidth
    yarl --> multidict
    yarl --> idna
    yarl --> propcache
    aiosignal --> typing_extensions
    aiosignal --> frozenlist
    multidict --> typing_extensions
    repomatic -.-> grp_docs
    repomatic -.-> grp_test
    repomatic -.-> grp_typing

    click accessible_pygments "https://pypi.org/project/accessible-pygments/" _blank
    click aiofiles "https://pypi.org/project/aiofiles/" _blank
    click aiohappyeyeballs "https://pypi.org/project/aiohappyeyeballs/" _blank
    click aiohttp "https://pypi.org/project/aiohttp/" _blank
    click aiosignal "https://pypi.org/project/aiosignal/" _blank
    click alabaster "https://pypi.org/project/alabaster/" _blank
    click arrow "https://pypi.org/project/arrow/" _blank
    click async_timeout "https://pypi.org/project/async-timeout/" _blank
    click attrs "https://pypi.org/project/attrs/" _blank
    click babel "https://pypi.org/project/babel/" _blank
    click backports_strenum "https://pypi.org/project/backports-strenum/" _blank
    click beautifulsoup4 "https://pypi.org/project/beautifulsoup4/" _blank
    click boltons "https://pypi.org/project/boltons/" _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 coverage "https://pypi.org/project/coverage/" _blank
    click deepmerge "https://pypi.org/project/deepmerge/" _blank
    click docutils "https://pypi.org/project/docutils/" _blank
    click exceptiongroup "https://pypi.org/project/exceptiongroup/" _blank
    click execnet "https://pypi.org/project/execnet/" _blank
    click extra_platforms "https://pypi.org/project/extra-platforms/" _blank
    click frozenlist "https://pypi.org/project/frozenlist/" _blank
    click furo "https://pypi.org/project/furo/" _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 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 multidict "https://pypi.org/project/multidict/" _blank
    click myst_parser "https://pypi.org/project/myst-parser/" _blank
    click packaging "https://pypi.org/project/packaging/" _blank
    click pluggy "https://pypi.org/project/pluggy/" _blank
    click propcache "https://pypi.org/project/propcache/" _blank
    click psutil "https://pypi.org/project/psutil/" _blank
    click py_walk "https://pypi.org/project/py-walk/" _blank
    click pyelftools "https://pypi.org/project/pyelftools/" _blank
    click pygments "https://pypi.org/project/pygments/" _blank
    click pyproject_metadata "https://pypi.org/project/pyproject-metadata/" _blank
    click pytest "https://pypi.org/project/pytest/" _blank
    click pytest_cov "https://pypi.org/project/pytest-cov/" _blank
    click pytest_github_actions_annotate_failures "https://pypi.org/project/pytest-github-actions-annotate-failures/" _blank
    click pytest_randomly "https://pypi.org/project/pytest-randomly/" _blank
    click pytest_xdist "https://pypi.org/project/pytest-xdist/" _blank
    click python_dateutil "https://pypi.org/project/python-dateutil/" _blank
    click pyyaml "https://pypi.org/project/pyyaml/" _blank
    click repomatic "https://pypi.org/project/repomatic/" _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 sly "https://pypi.org/project/sly/" _blank
    click snowballstemmer "https://pypi.org/project/snowballstemmer/" _blank
    click soupsieve "https://pypi.org/project/soupsieve/" _blank
    click sphinx "https://pypi.org/project/sphinx/" _blank
    click sphinx_autodoc_typehints "https://pypi.org/project/sphinx-autodoc-typehints/" _blank
    click sphinx_basic_ng "https://pypi.org/project/sphinx-basic-ng/" _blank
    click sphinx_copybutton "https://pypi.org/project/sphinx-copybutton/" _blank
    click sphinx_datatables "https://pypi.org/project/sphinx-datatables/" _blank
    click sphinx_design "https://pypi.org/project/sphinx-design/" _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_jquery "https://pypi.org/project/sphinxcontrib-jquery/" _blank
    click sphinxcontrib_jsmath "https://pypi.org/project/sphinxcontrib-jsmath/" _blank
    click sphinxcontrib_mermaid "https://pypi.org/project/sphinxcontrib-mermaid/" _blank
    click sphinxcontrib_qthelp "https://pypi.org/project/sphinxcontrib-qthelp/" _blank
    click sphinxcontrib_serializinghtml "https://pypi.org/project/sphinxcontrib-serializinghtml/" _blank
    click sphinxext_opengraph "https://pypi.org/project/sphinxext-opengraph/" _blank
    click tabulate "https://pypi.org/project/tabulate/" _blank
    click tomli "https://pypi.org/project/tomli/" _blank
    click tomlrt "https://pypi.org/project/tomlrt/" _blank
    click types_boltons "https://pypi.org/project/types-boltons/" _blank
    click types_docutils "https://pypi.org/project/types-docutils/" _blank
    click types_pyyaml "https://pypi.org/project/types-pyyaml/" _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 vt_py "https://pypi.org/project/vt-py/" _blank
    click wcmatch "https://pypi.org/project/wcmatch/" _blank
    click wcwidth "https://pypi.org/project/wcwidth/" _blank
    click yarl "https://pypi.org/project/yarl/" _blank

    style repomatic stroke-width:3px
    style arrow stroke-width:3px
    style backports_strenum stroke-width:3px
    style boltons stroke-width:3px
    style click_extra stroke-width:3px
    style coverage stroke-width:3px
    style extra_platforms stroke-width:3px
    style furo stroke-width:3px
    style myst_parser stroke-width:3px
    style packaging stroke-width:3px
    style py_walk stroke-width:3px
    style pyelftools stroke-width:3px
    style pyproject_metadata stroke-width:3px
    style pytest stroke-width:3px
    style pytest_cov stroke-width:3px
    style pytest_github_actions_annotate_failures stroke-width:3px
    style pytest_randomly stroke-width:3px
    style pytest_xdist stroke-width:3px
    style pyyaml stroke-width:3px
    style sphinx stroke-width:3px
    style sphinx_autodoc_typehints stroke-width:3px
    style sphinx_copybutton stroke-width:3px
    style sphinx_datatables stroke-width:3px
    style sphinx_design stroke-width:3px
    style sphinxcontrib_jquery stroke-width:3px
    style sphinxcontrib_mermaid stroke-width:3px
    style sphinxext_opengraph stroke-width:3px
    style tomlrt stroke-width:3px
    style types_boltons stroke-width:3px
    style types_docutils stroke-width:3px
    style types_pyyaml stroke-width:3px
    style vt_py stroke-width:3px
    style wcmatch stroke-width:3px

    style primary-deps fill:#1565C020,stroke:#42A5F5
    style grp_docs fill:#546E7A20,stroke:#90A4AE
    style grp_test fill:#546E7A20,stroke:#90A4AE
    style grp_typing fill:#546E7A20,stroke:#90A4AE

    

Build backends

A repomatic-managed project declares uv_build as its build backend. Distribution channels do not all have it: a packager whose toolchain predates uv-build, or whose policy forbids fetching it, falls back to setuptools, and setuptools then runs its own automatic package discovery over the repository root.

That discovery fails on any repository holding more than one top-level directory, which is every project of this shape:

error: Multiple top-level packages discovered in a flat-layout: ['docs', 'tests', 'my_package'].

The fix is one section naming the package explicitly:

[tool.setuptools]
# Distributors lacking uv-build fall back to setuptools, whose automatic
# discovery then sees docs/, tests/ and every other top-level directory as a
# package and fails. uv-build ignores this section entirely, relying on
# [tool.uv] build-backend instead, so it costs a released wheel nothing.
packages.find.include = ["my_package*"]

Two things make this worth knowing rather than obvious. It is invisible upstream: uv build, uv sync and every wheel published from CI ignore the section, so the failure only ever appears in a downstream packager’s build log, usually weeks after the release that introduced the second top-level directory. And the trailing * matters, since it is what keeps subpackages in.

repomatic init does not write this section. The value it must carry is the package’s own import name, and a bundled template can only approximate that with a list of directories to exclude, which is a worse default than the one line a project can write once and never revisit.