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.dev2.tar.gz (13.7 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.dev2-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: shushpy-0.0.1.dev2.tar.gz
  • Upload date:
  • Size: 13.7 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.dev2.tar.gz
Algorithm Hash digest
SHA256 c94317ad6d134d7cdcf0bcf7537f73ac8c7aab70f7690f22de23f439ad5bc493
MD5 2bebb21789718f96b3cb4a8d87d0d914
BLAKE2b-256 9c0a4a80f62eb21326f86e7d51620538faf737796f4d8a0634419c68a5d927d3

See more details on using hashes here.

File details

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

File metadata

  • Download URL: shushpy-0.0.1.dev2-py3-none-any.whl
  • Upload date:
  • Size: 11.0 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.dev2-py3-none-any.whl
Algorithm Hash digest
SHA256 bd5b29ee35bcf76b7ec7d3c679eef362ecc2cd8e0d738818c1822573fdc5be65
MD5 62cc40f555a8a855b1d3ef1812cb7fe2
BLAKE2b-256 642644516bac13959d9be5b5019fd6176abc7bc72acda7c21a36f58aad75f559

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