Skip to content

Index

uv

Canonical uv-workspace resolution surface.

Member dataclass

A single uv-workspace member.

Attributes:

Name Type Description
name str

Directory name of the member.

path Path

Absolute, resolved path to the member directory.

Source code in packages/axm-ingot/src/axm_ingot/uv/models.py
Python
@dataclass(frozen=True)
class Member:
    """A single uv-workspace member.

    Attributes:
        name: Directory name of the member.
        path: Absolute, resolved path to the member directory.
    """

    name: str
    path: Path

ResolvedWorkspace dataclass

A uv workspace with its resolved members.

Attributes:

Name Type Description
root Path

Absolute path to the workspace root (holding the root pyproject).

members tuple[Member, ...]

Members sorted by name.

Source code in packages/axm-ingot/src/axm_ingot/uv/models.py
Python
@dataclass(frozen=True)
class ResolvedWorkspace:
    """A uv workspace with its resolved members.

    Attributes:
        root: Absolute path to the workspace root (holding the root pyproject).
        members: Members sorted by name.
    """

    root: Path
    members: tuple[Member, ...]

find_project_root(start)

Walk parents from start to the first directory holding any pyproject.

Returns the directory of the first ancestor (start included) that contains a pyproject.toml -- any project, not necessarily a uv workspace. start is resolved first; a file start is anchored on its parent directory. Unlike :func:find_workspace_root, this never returns None: with no pyproject.toml in any ancestor it falls back to the (resolved) starting directory.

Source code in packages/axm-ingot/src/axm_ingot/uv/resolve.py
Python
def find_project_root(start: Path) -> Path:
    """Walk parents from ``start`` to the first directory holding any pyproject.

    Returns the directory of the first ancestor (``start`` included) that
    contains a ``pyproject.toml`` -- any project, not necessarily a uv
    workspace. ``start`` is resolved first; a file ``start`` is anchored on its
    parent directory. Unlike :func:`find_workspace_root`, this never returns
    ``None``: with no ``pyproject.toml`` in any ancestor it falls back to the
    (resolved) starting directory.
    """
    current = start.resolve()
    if current.is_file():
        current = current.parent
    for candidate in (current, *current.parents):
        if (candidate / _PYPROJECT).is_file():
            return candidate
    return current

find_workspace_root(path)

Walk parents from path to the first uv-workspace root.

Returns the directory of the first ancestor (path included) whose pyproject.toml carries a [tool.uv.workspace] section, else None.

Source code in packages/axm-ingot/src/axm_ingot/uv/resolve.py
Python
def find_workspace_root(path: Path) -> Path | None:
    """Walk parents from ``path`` to the first uv-workspace root.

    Returns the directory of the first ancestor (``path`` included) whose
    ``pyproject.toml`` carries a ``[tool.uv.workspace]`` section, else ``None``.
    """
    current = path.resolve()
    for directory in (current, *current.parents):
        data = _load_pyproject(directory)
        if data is not None and _get_workspace_config(data) is not None:
            return directory
    return None

parse_workspace_members(text)

Extract the raw [tool.uv.workspace].members from pyproject text.

Pure-string helper: parses text with :func:tomllib.loads and returns the declared members verbatim -- no glob expansion, no filesystem access, no exclude/require_pyproject filtering. Globs (packages/*) and literal entries are returned exactly as written. Defensive: malformed TOML or an absent [tool.uv.workspace] table yields [] rather than raising.

Parameters:

Name Type Description Default
text str

Raw pyproject.toml content.

required

Returns:

Type Description
list[str]

The raw member strings declared under [tool.uv.workspace].members,

list[str]

or [] when none are declared.

Source code in packages/axm-ingot/src/axm_ingot/uv/resolve.py
Python
def parse_workspace_members(text: str) -> list[str]:
    """Extract the raw ``[tool.uv.workspace].members`` from pyproject text.

    Pure-string helper: parses ``text`` with :func:`tomllib.loads` and returns
    the declared members verbatim -- no glob expansion, no filesystem access,
    no ``exclude``/``require_pyproject`` filtering. Globs (``packages/*``) and
    literal entries are returned exactly as written. Defensive: malformed TOML
    or an absent ``[tool.uv.workspace]`` table yields ``[]`` rather than raising.

    Args:
        text: Raw ``pyproject.toml`` content.

    Returns:
        The raw member strings declared under ``[tool.uv.workspace].members``,
        or ``[]`` when none are declared.
    """
    try:
        data = tomllib.loads(text)
    except tomllib.TOMLDecodeError:
        return []
    workspace = _get_workspace_config(data)
    if workspace is None:
        return []
    members = workspace.get("members")
    if not isinstance(members, list):
        return []
    return [str(member) for member in members]

resolve_workspace(pyproject_dir)

Resolve the uv workspace rooted at pyproject_dir.

Parses [tool.uv.workspace].members, resolves the globs to directories, subtracts the exclude globs, keeps only directories that contain a pyproject.toml (require_pyproject), and returns the members sorted by name. Returns None when pyproject_dir is not a uv workspace or its pyproject is missing/malformed.

Source code in packages/axm-ingot/src/axm_ingot/uv/resolve.py
Python
def resolve_workspace(pyproject_dir: Path) -> ResolvedWorkspace | None:
    """Resolve the uv workspace rooted at ``pyproject_dir``.

    Parses ``[tool.uv.workspace].members``, resolves the globs to directories,
    subtracts the ``exclude`` globs, keeps only directories that contain a
    ``pyproject.toml`` (``require_pyproject``), and returns the members sorted
    by name. Returns ``None`` when ``pyproject_dir`` is not a uv workspace or
    its pyproject is missing/malformed.
    """
    root = pyproject_dir.resolve()
    data = _load_pyproject(root)
    if data is None:
        return None
    workspace = _get_workspace_config(data)
    if workspace is None:
        return None

    included = _resolve_glob_dirs(root, workspace.get("members"))
    excluded = _resolve_glob_dirs(root, workspace.get("exclude"))
    members = tuple(
        sorted(
            (
                Member(name=directory.name, path=directory)
                for directory in included - excluded
                if (directory / _PYPROJECT).is_file()
            ),
            key=lambda member: member.name,
        )
    )
    return ResolvedWorkspace(root=root, members=members)