oct
Loading...
Searching...
No Matches
build_artifacts Namespace Reference

Functions

tuple[bool, str] _looks_like_packaging_output (Path target)
tuple[int, list[Path]] clean_build_dirs (Path root, bool dry_run=False)

Variables

tuple _DISTRIBUTION_MARKERS = ("pyproject.toml", "setup.py", "setup.cfg")
frozenset _EXTRA_PRUNE_DIRS
tuple _BUILD_ENTRY_PATTERNS
tuple _DIST_ENTRY_PATTERNS

Detailed Description

Purpose
-------
Remove the ``build/`` and ``dist/`` trees that Python packaging tools
leave behind, for :command:`oct clean`.

These are not merely untidy. A stale ``build/lib/<pkg>`` is a complete
second copy of a package's source, and on 2026-09-26 it cost real time
twice in one session: ``oct docs`` auto-discovery ran ``sphinx-apidoc``
over both the live package and the build copy, and Doxygen's recursive
scan ingested ``templates/claude_skills/*/SKILL.md`` from both, putting
16 duplicate pages in one sidebar. Anything that walks a project tree
sees the copy, and the copy is arbitrarily old.

Responsibilities
----------------
- Provide :func:`clean_build_dirs`, matching the ``(removed, failed)``
  contract of the cleaners in :mod:`oct.tools.source_exporter`.
- Refuse to delete a ``build`` or ``dist`` directory that does not
  demonstrably hold packaging output, and say so rather than passing
  over it in silence.

Diagnostics
-----------
Domain: OCT-CORE
Levels:
    L2 - sweep entry / exit
    L3 - per-directory decision
    L4 - shape-check detail

Contracts
---------
- Name matching alone NEVER authorises a delete. ``build`` and ``dist``
  are ordinary English words and a project is entitled to a source
  directory called either. Every candidate must also (a) sit directly
  beside a ``pyproject.toml`` or ``setup.py``, so it belongs to a Python
  distribution root, and (b) contain nothing but the entries the
  packaging tools themselves produce. A candidate failing either test is
  left alone with a printed note.
- An empty ``build``/``dist`` beside a distribution root IS removable:
  the tools create the directory before filling it, so an interrupted
  build can leave it bare.
- Removal failure is reported, never raised. :command:`oct clean` sweeps
  several categories and one unremovable tree must not abort the rest.

Dependencies
------------
- oct.core.exclusions (COMMON_EXCLUDE_DIRS - directories not worth walking)
- oct.core.diagnostics (_dbg structured logger)
- oct.tools.fs_remove (remove_tree_force)

Function Documentation

◆ _looks_like_packaging_output()

tuple[bool, str] build_artifacts._looks_like_packaging_output ( Path target)
protected
Return ``(is_packaging_output, reason)`` for a ``build``/``dist`` dir.

*reason* is meaningful only when the answer is False, and distinguishes
two cases the caller reports differently:

- **Empty string** - never a candidate. No distribution marker sits
  beside it, so the name is a coincidence and there is nothing to
  tell the operator. Most directories called ``dist`` in a tree with
  any JavaScript in it land here, and announcing each one would bury
  the real output.
- **Non-empty** - it WAS a candidate (marker present) and was refused
  on its contents. That is worth printing: it names the entry that
  stopped the delete, so the operator can see whether the refusal was
  right.

Definition at line 94 of file build_artifacts.py.

Here is the caller graph for this function:

◆ clean_build_dirs()

tuple[int, list[Path]] build_artifacts.clean_build_dirs ( Path root,
bool dry_run = False )
Remove packaging ``build/`` and ``dist/`` trees under *root*.

Parameters
----------
root
    Directory to sweep. Walked recursively, skipping the usual
    uninteresting directories (``.git``, ``.venv``, ``__pycache__``
    and the rest of :data:`COMMON_EXCLUDE_DIRS`) plus
    :data:`_EXTRA_PRUNE_DIRS`.
dry_run
    Report what would be removed without touching the filesystem.

Returns
-------
tuple[int, list[Path]]
    ``(removed, failed)`` - *removed* counts directories that are
    gone (or would be, under *dry_run*); *failed* lists those still
    present afterwards. Directories refused by the shape check are in
    neither: nothing was attempted on them, so counting them as
    failures would misreport a correct refusal as a problem.

Definition at line 136 of file build_artifacts.py.

Here is the call graph for this function:

Variable Documentation

◆ _BUILD_ENTRY_PATTERNS

tuple build_artifacts._BUILD_ENTRY_PATTERNS
protected
Initial value:
1= (
2 "lib", "lib.*", "bdist.*", "scripts-*", "temp.*", "html", "doctrees",
3)

Definition at line 84 of file build_artifacts.py.

◆ _DIST_ENTRY_PATTERNS

tuple build_artifacts._DIST_ENTRY_PATTERNS
protected
Initial value:
1= (
2 "*.whl", "*.tar.gz", "*.zip", "*.egg", "*.exe", "*.msi",
3)

Definition at line 89 of file build_artifacts.py.

◆ _DISTRIBUTION_MARKERS

tuple build_artifacts._DISTRIBUTION_MARKERS = ("pyproject.toml", "setup.py", "setup.cfg")
protected

Definition at line 71 of file build_artifacts.py.

◆ _EXTRA_PRUNE_DIRS

frozenset build_artifacts._EXTRA_PRUNE_DIRS
protected
Initial value:
1= frozenset({
2 "node_modules", ".tox", ".nox", ".mypy_cache", ".pytest_cache",
3 "site-packages",
4})

Definition at line 77 of file build_artifacts.py.