Skip to main content

Remove all comments and docstrings from Python code using a safe AST-based transform.

Project description

shushpy

Remove all comments and docstrings from Python code using a safe AST-based transform.

  • Inline comments (e.g., # comment) are dropped.
  • Module/class/function docstrings are removed.
  • The code is re-generated via ast.unparse, so formatting may change, but semantics are preserved.

Python 3.12+ required. Zero third-party dependencies.

Why this exists

  • You need to distribute or compare Python sources without any comments or docstrings.
  • You want a robust approach that won’t break on edge-case syntax or string tricks—AST transformations operate on parsed code, not raw text, so it’s resilient.

Installation and usage with uv

Prerequisites:

  • Python 3.12+
  • uv installed

Clone and set up the project environment:

# clone the repository
git clone https://github.com/vodkar/shushpy.git
cd shushpy

# create a project environment and install dependencies + the project
uv sync

You can run the CLI via uv without manually activating the virtual environment:

# show CLI help
uv run shushpy --help

# strip a single file to stdout
uv run shushpy path/to/file.py

# strip a directory recursively in-place
uv run shushpy src/ --inplace

# read from stdin, write to stdout
cat script.py | uv run shushpy

Alternatively, if you prefer explicit installation into the environment:

uv pip install -e .

Then you can use the console script directly:

shushpy --help

CLI

usage: shushpy [-h] [--inplace] [--encoding ENCODING] [--recursive] [--no-recursive]
                   [--log-level {CRITICAL,ERROR,WARNING,INFO,DEBUG}]
                   [paths ...]

Remove all comments and docstrings from Python code.

positional arguments:
  paths                 Files or directories to process. If omitted, read from stdin and write to stdout.

options:
  -h, --help            show this help message and exit
  --inplace             Rewrite files in place. Required for multiple-file outputs.
  --encoding ENCODING   Text encoding for reading/writing files (default: utf-8).
  --recursive           Recurse into subdirectories (default: enabled).
  --no-recursive        Disable recursion when processing directories.
  --log-level           Set the logging level (default: WARNING).

Notes:

  • When not using --inplace, the CLI writes to stdout. If your input expands to multiple files, the CLI refuses to stream multiple outputs to stdout—use --inplace in that case.
  • When no paths are provided, the CLI reads from stdin and writes to stdout.

Library usage

The library exposes a focused API in the shushpy package.

  • strip_comments(source: str) -> str
  • strip_file(path: str | Path, *, inplace: bool = False, encoding: str = "utf-8") -> str
  • strip_path(path: str | Path, *, inplace: bool = False, encoding: str = "utf-8", recursive: bool = True) -> dict[str, str]
  • strip_paths(paths: list[str | Path], *, inplace: bool = False, encoding: str = "utf-8", recursive: bool = True) -> dict[str, str]

Minimal examples:

from __future__ import annotations

from pathlib import Path
from typing import Final

from shushpy import strip_comments, strip_file, strip_path, strip_paths

# Example 1: Process a source string
SOURCE: Final[str] = """
\"\"\"Module docstring\"\"\"

def add(a: int, b: int) -> int:
    \"\"\"Add two numbers\"\"\"
    return a + b  # inline comment
"""
cleaned: str = strip_comments(SOURCE)
print(cleaned)

# Example 2: Process a single file to a string (no in-place modification)
result_str: str = strip_file("path/to/file.py", inplace=False)

# Example 3: Process a directory recursively, in place
modified: dict[str, str] = strip_path("src", inplace=True, recursive=True)

# Example 4: Process multiple mixed paths, no in-place (returns mapping path->content)
collected: dict[str, str] = strip_paths([Path("a.py"), Path("pkg/")], inplace=False)

Behavior and guarantees

  • AST-based: The tool parses Python code into an AST, removes docstrings via AST transformation, and regenerates the code via ast.unparse. Inline/block comments aren’t part of the AST, so they never appear in the output.
  • Formatting: The output is re-generated source. Expect normalized formatting and possibly different quoting styles or minor layout changes.
  • Errors: Invalid Python raises SyntaxError. I/O and encoding issues are surfaced with clear errors.
  • Scope: Docstrings are removed at module, class, and (async) function levels.

Development

Common workflows with uv:

# create or update the environment and install the project
uv sync

# run the CLI
uv run shushpy --help

# run the module directly
uv run python -m shushpy.cli --help

# build distributions (wheel and sdist)
uv build

Project metadata:

  • Build backend: Hatchling
  • Console script: shushpy (entry point at shushpy.cli:main)

Release & Publishing

Checklist before release:

  • Ensure you have a PyPI account and access to the project name "shushpy" (or choose a unique name).
  • Create a PyPI API token and add it as a GitHub Secret named PYPI_API_TOKEN in the repository settings.
  • Bump the version in pyproject.toml under [project] version to the new semantic version (e.g., "0.1.1").
  • Update README and (optionally) a CHANGELOG with notable changes.
  • Run tests locally:
    • uv sync
    • uv run pytest -q
  • Build locally to verify artifacts:
    • uv build
  • Commit and tag the release:
    • git add .
    • git commit -m "Release vX.Y.Z"
    • git tag vX.Y.Z
    • git push && git push --tags

Publishing options:

  • GitHub Actions (recommended):
    • On pushing a tag like vX.Y.Z (or publishing a GitHub Release), the workflow at .github/workflows/publish.yml will:
      • Install deps with uv, run tests, build distributions, and publish to PyPI using PYPI_API_TOKEN.
  • Manual (optional):

Post-release verification:

  • Install from PyPI and check CLI:
    • uvx pip install shushpy
    • uvx shushpy --help

Limitations

  • This tool removes docstrings and comments only; it does not attempt to remove dead code or perform obfuscation.
  • Because output is regenerated, stable formatting is not guaranteed across Python minor versions if ast.unparse behavior changes.
  • Python 3.12+ is required (uses modern ast behavior and typing features).

License

See the repository’s LICENSE file.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shushpy-0.0.1.dev3.tar.gz (14.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shushpy-0.0.1.dev3-py3-none-any.whl (11.4 kB view details)

Uploaded Python 3

File details

Details for the file shushpy-0.0.1.dev3.tar.gz.

File metadata

  • Download URL: shushpy-0.0.1.dev3.tar.gz
  • Upload date:
  • Size: 14.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for shushpy-0.0.1.dev3.tar.gz
Algorithm Hash digest
SHA256 39972fddd3df07ba79799ee5a37592ec5ab84749bb00257e63c8a8afbe5a0737
MD5 b94d835857871d805e07566e47ea0c8a
BLAKE2b-256 b2e6e8b0980fa3dfb47a85ae37d200620e5c6f9b2d80f24ef434f5f0518e8a8f

See more details on using hashes here.

File details

Details for the file shushpy-0.0.1.dev3-py3-none-any.whl.

File metadata

  • Download URL: shushpy-0.0.1.dev3-py3-none-any.whl
  • Upload date:
  • Size: 11.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for shushpy-0.0.1.dev3-py3-none-any.whl
Algorithm Hash digest
SHA256 ff4fa389c7a773b91f7e604c787bfabe16f4895e5df1f013c23b45951353a4af
MD5 54f59b691b380c527880d3e6fbaa359a
BLAKE2b-256 37e6f4e07514d6c67347910684adadc32dc58e12149cee6d95f0c79c62e6b071

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page