Skip to content

Conversation

@cpsievert
Copy link
Collaborator

@cpsievert cpsievert commented Dec 18, 2025

Partly addresses #2125

This PR removes the shiny/api-examples/ directory from the distributed package (both wheels and source distributions) to reduce package size and file count. The examples are only needed during documentation builds, which always run from the source repository.

Motivation

The api-examples/ directory contains ~310 example files used by the @add_example() decorator to inject code examples into docstrings during documentation generation. These files:

  • Are only accessed when SHINY_ADD_EXAMPLES=true (set during make docs-quartodoc)
  • Are never needed by end users installing the package
  • Added ~400KB to the package size
  • Contributed ~36% of the total file count in the wheel

Similar to development dependencies, these are build-time artifacts that don't belong in the runtime package.

Changes

1. MANIFEST.in

- recursive-include shiny/api-examples *
+ prune shiny/api-examples
+ prune shiny/experimental/api-examples

Why: Controls what goes into source distributions (.tar.gz). The prune directive explicitly excludes the directories.

2. pyproject.toml

 [tool.setuptools]
-packages = { find = { include = ["shiny", "shiny.*"] } }
+[tool.setuptools.packages.find]
+where = ["."]
+include = ["shiny*"]
+namespaces = false
+
+[tool.setuptools.exclude-package-data]
+"*" = ["api-examples/**"]

Why: Controls what goes into binary wheels (.whl):

  1. packages.find: Expanded from inline syntax to dedicated section for better control
  2. exclude-package-data: Explicit blacklist for api-examples as additional safeguard

Why both MANIFEST.in and pyproject.toml?

These control different build artifacts:

  • MANIFEST.in → Source distributions (.tar.gz) - used by some users, required by PyPI
  • pyproject.toml → Binary wheels (.whl) - used by most users via pip install

The wheel build process doesn't read MANIFEST.in; it uses setuptools configuration from pyproject.toml. We need to exclude api-examples from both to ensure they don't appear in either distribution format.

3. shiny/_docstring.py

def find_api_examples_dir(start_dir: str) -> Optional[str]:
    # ... search for api-examples ...

    # Not found - provide helpful error for documentation builders
    if os.getenv("SHINY_ADD_EXAMPLES") == "true":
        raise FileNotFoundError(
            "Could not find 'api-examples/' directory. "
            "Documentation must be built from the source repository, "
            "not from an installed package. "
            f"Searched from: {search_start}"
        )
    return None

Why: Provides a clear error message if someone attempts to build docs from an installed package instead of from source.

Remove api-examples directory from the wheel distribution to reduce
package size by ~400KB. The examples are only needed during documentation
builds, which always run from the source repository.

Changes:
- Update MANIFEST.in to prune api-examples directories
- Configure setuptools to explicitly exclude api-examples from package data
- Add clear error message when docs are built from installed package
- Document that api-examples require source repository

The documentation build workflow is unchanged and continues to work
from the source tree where api-examples are present.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@cpsievert cpsievert requested a review from Copilot December 18, 2025 01:37
@cpsievert cpsievert changed the title feat: Don't bundle api-example in wheel distribution feat: Don't bundle api-examples in wheel distribution Dec 18, 2025

This comment was marked as resolved.

cpsievert and others added 3 commits December 17, 2025 19:42
Simplify package-data wildcards from redundant patterns to cleaner syntax:
- "www/**/*" → "www/**"
- "templates/**/*" → "templates/**"
- "api-examples/**/*" → "api-examples/**"

The `**` glob pattern already matches all files and subdirectories
recursively, making the `/*` suffix redundant.

Verified that the wheel still:
- Includes 662 www/templates files
- Excludes all api-examples files
- Maintains same 3.6MB size

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The `[tool.setuptools.package-data]` section specifying `www/**` and
`templates/**` was redundant because MANIFEST.in already includes these
with `recursive-include` directives.

MANIFEST.in directives are respected by both:
- Source distribution builds (sdist)
- Binary wheel builds (wheel)

Only `exclude-package-data` is needed in pyproject.toml to explicitly
exclude api-examples, since MANIFEST.in's `prune` directive alone isn't
sufficient for wheel builds.

Final configuration is now minimal and clean:
- MANIFEST.in handles all includes (www, templates)
- pyproject.toml handles only the exclude (api-examples)

Verified wheel still contains:
- 518 www files
- 144 template files
- 0 api-examples files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@cpsievert cpsievert force-pushed the feat/rm-api-examples branch from 003c97d to ffafccb Compare December 18, 2025 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants