Claude Code for py_compile: Python Source File Compilation — Claude Skills 360 Blog
Blog / AI / Claude Code for py_compile: Python Source File Compilation
AI

Claude Code for py_compile: Python Source File Compilation

Published: December 7, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s py_compile module compiles a single .py source file to a .pyc bytecode file. import py_compile. Compile: py_compile.compile(file, cfile=None, dfile=None, doraise=False, optimize=-1, invalidation_mode=PycInvalidationMode.TIMESTAMP, quiet=0)file is the source path; cfile overrides the output .pyc path (defaults to __pycache__/file.cpython-XY.pyc); dfile sets the filename embedded in tracebacks; doraise=True raises PyCompileError on syntax errors instead of returning None; optimize is 0 (no optimization), 1 (strip asserts), or 2 (strip docstrings); invalidation_mode controls stale-bytecode detection. Invalidation modes: PycInvalidationMode.TIMESTAMP (default) — mtime+size check; PycInvalidationMode.CHECKED_HASH — SHA-256 hash of source checked at import; PycInvalidationMode.UNCHECKED_HASH — hash embedded but not checked (fastest runtime). Error: py_compile.PyCompileError(exc_type, exc_value, file, msg) raised on doraise=True; .msg contains the formatted error. py_compile.main() — command-line interface (python -m py_compile file.py). Claude Code generates pre-compilation pipelines, deploy validators, syntax checkers, and bytecode cache warmers.

CLAUDE.md for py_compile

## py_compile Stack
- Stdlib: import py_compile
- Compile: py_compile.compile("app.py", doraise=True)
- Optimize: py_compile.compile("app.py", optimize=2)   # strip docstrings
- Error:    try: py_compile.compile(f, doraise=True)
-           except py_compile.PyCompileError as e: print(e.msg)
- CLI:      python -m py_compile file1.py file2.py
- Note:     compileall for batch compilation of packages

py_compile Compilation Pipeline

# app/py_compileutil.py — single compile, syntax check, batch, validate
from __future__ import annotations

import io
import os
import py_compile
import sys
from dataclasses import dataclass, field
from pathlib import Path


# ─────────────────────────────────────────────────────────────────────────────
# 1. Single-file helpers
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class CompileResult:
    source:  Path
    success: bool
    output:  "Path | None" = None
    error:   str = ""

    def __str__(self) -> str:
        if self.success:
            return f"OK  {self.source}{self.output}"
        return f"ERR {self.source}: {self.error}"


def compile_file(
    source: "str | Path",
    output: "str | Path | None" = None,
    optimize: int = -1,
    invalidation_mode: py_compile.PycInvalidationMode = py_compile.PycInvalidationMode.TIMESTAMP,
) -> CompileResult:
    """
    Compile a single .py file to .pyc. Returns a CompileResult.

    Example:
        result = compile_file("app/main.py")
        if not result.success:
            print(result.error)
    """
    src = Path(source)
    cfile = str(output) if output else None
    try:
        out = py_compile.compile(
            str(src),
            cfile=cfile,
            doraise=True,
            optimize=optimize,
            invalidation_mode=invalidation_mode,
        )
        return CompileResult(source=src, success=True, output=Path(out))
    except py_compile.PyCompileError as e:
        return CompileResult(source=src, success=False, error=e.msg)


def is_valid_python(source: "str | Path") -> bool:
    """
    Return True if source is a syntactically valid Python file.

    Example:
        if not is_valid_python("script.py"):
            print("syntax error")
    """
    return compile_file(source).success


def check_syntax(source: "str | Path") -> "str | None":
    """
    Return a syntax error message string if present, else None.

    Example:
        err = check_syntax("broken.py")
        if err:
            print(f"Syntax error: {err}")
    """
    result = compile_file(source)
    return None if result.success else result.error


# ─────────────────────────────────────────────────────────────────────────────
# 2. Batch compilation
# ─────────────────────────────────────────────────────────────────────────────

def compile_directory(
    root: "str | Path",
    optimize: int = -1,
    recursive: bool = True,
    skip_errors: bool = True,
) -> list[CompileResult]:
    """
    Compile all .py files under root.
    Returns a list of CompileResult (one per file).

    Example:
        results = compile_directory("src/myapp")
        errors = [r for r in results if not r.success]
        if errors:
            for r in errors:
                print(r)
    """
    root = Path(root)
    pattern = "**/*.py" if recursive else "*.py"
    results = []
    for py_file in sorted(root.glob(pattern)):
        result = compile_file(py_file, optimize=optimize)
        results.append(result)
        if not result.success and not skip_errors:
            raise py_compile.PyCompileError(
                SyntaxError, result.error, str(py_file), result.error
            )
    return results


def syntax_check_files(paths: list["str | Path"]) -> dict[str, "str | None"]:
    """
    Check multiple files for syntax errors.
    Returns {filename: error_message_or_None}.

    Example:
        report = syntax_check_files(["a.py", "b.py", "c.py"])
        for name, err in report.items():
            if err:
                print(f"FAIL {name}: {err}")
            else:
                print(f"OK   {name}")
    """
    return {
        str(p): check_syntax(p)
        for p in paths
    }


# ─────────────────────────────────────────────────────────────────────────────
# 3. Compile string source (check without a file)
# ─────────────────────────────────────────────────────────────────────────────

def compile_source_string(
    source: str,
    filename: str = "<string>",
    optimize: int = 0,
) -> "tuple[bool, str]":
    """
    Compile a Python source string to bytecode (using builtins.compile).
    Returns (ok, error_message). Does not write a .pyc file.

    Example:
        ok, err = compile_source_string("x = 1 +")
        print(ok, err)  # False, "invalid syntax"
    """
    try:
        compile(source, filename, "exec", optimize=optimize)
        return True, ""
    except SyntaxError as e:
        return False, f"{e.__class__.__name__}: {e.msg} (line {e.lineno})"
    except Exception as e:
        return False, str(e)


# ─────────────────────────────────────────────────────────────────────────────
# 4. Deployment pre-compilation validator
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class DeployValidation:
    """
    Run syntax checks on all Python files in a project before deployment.

    Example:
        v = DeployValidation("src/myapp")
        v.run()
        if v.has_errors:
            v.print_report()
            sys.exit(1)
    """
    root:     Path
    results:  list[CompileResult] = field(default_factory=list)

    def __post_init__(self) -> None:
        self.root = Path(self.root)

    def run(self, optimize: int = 0) -> "DeployValidation":
        """Run compilation on all .py files under root."""
        self.results = compile_directory(self.root, optimize=optimize, skip_errors=True)
        return self

    @property
    def has_errors(self) -> bool:
        return any(not r.success for r in self.results)

    @property
    def error_count(self) -> int:
        return sum(1 for r in self.results if not r.success)

    @property
    def ok_count(self) -> int:
        return sum(1 for r in self.results if r.success)

    def print_report(self, file=None) -> None:
        """Print a summary report to file (default: stderr)."""
        f = file or sys.stderr
        total = len(self.results)
        print(f"Syntax validation: {self.ok_count}/{total} OK, "
              f"{self.error_count} errors", file=f)
        for r in self.results:
            if not r.success:
                print(f"  FAIL {r.source.relative_to(self.root)}: {r.error}", file=f)


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    import tempfile

    print("=== py_compile demo ===")

    # ── compile_file ──────────────────────────────────────────────────────────
    print("\n--- compile_file ---")
    with tempfile.TemporaryDirectory() as td:
        # Write a valid file
        good = Path(td) / "good.py"
        good.write_text("def hello():\n    return 'hello'\n")
        result = compile_file(good)
        print(f"  {result}")

        # Write a bad file
        bad = Path(td) / "bad.py"
        bad.write_text("def broken(\n")
        result_bad = compile_file(bad)
        print(f"  {result_bad}")

    # ── compile_directory ─────────────────────────────────────────────────────
    print("\n--- compile_directory ---")
    with tempfile.TemporaryDirectory() as td:
        (Path(td) / "a.py").write_text("x = 1\n")
        (Path(td) / "b.py").write_text("y = 2\n")
        (Path(td) / "broken.py").write_text("class X\n")
        results = compile_directory(td, recursive=False)
        for r in results:
            rel = Path(r.source).name
            print(f"  {rel}: {'OK' if r.success else 'ERR'}")

    # ── compile_source_string ─────────────────────────────────────────────────
    print("\n--- compile_source_string ---")
    cases = [
        "x = 1 + 2",
        "def f(): pass",
        "x = 1 +",
        "for",
    ]
    for src in cases:
        ok, err = compile_source_string(src)
        status = "OK " if ok else f"ERR: {err}"
        print(f"  {src!r[:25]:27}{status}")

    # ── DeployValidation ──────────────────────────────────────────────────────
    print("\n--- DeployValidation ---")
    with tempfile.TemporaryDirectory() as td:
        (Path(td) / "app.py").write_text("import os\nprint(os.getcwd())\n")
        (Path(td) / "util.py").write_text("def helper(): return 42\n")
        (Path(td) / "config.py").write_text("settings = {\n")  # syntax error
        v = DeployValidation(td).run()
        v.print_report(file=sys.stdout)

    # ── py_compile.PycInvalidationMode ───────────────────────────────────────
    print("\n--- PycInvalidationMode values ---")
    for mode in py_compile.PycInvalidationMode:
        print(f"  {mode.name} = {mode.value}")

    print("\n=== done ===")

For the compileall alternative — python -m compileall mypackage/ and compileall.compile_dir(path) recursively compile all .py files in a package tree using multiprocessing — use compileall for batch production pre-compilation; use py_compile.compile() when you need single-file control, custom output paths, detailed error objects, or integration into a CI build pipeline. For the ast.parse / compile() built-in alternative — ast.parse(source) parses source into an AST without writing bytecode; compile(source, filename, "exec") compiles to a code object in memory — use ast.parse when you want to inspect or transform the syntax tree; use py_compile.compile when you want the standard __pycache__ artifact; use the built-in compile() when you need a code object for exec() or eval(). The Claude Skills 360 bundle includes py_compile skill sets covering CompileResult dataclass and compile_file() single-file compiler, is_valid_python()/check_syntax() boolean and message helpers, compile_directory()/syntax_check_files() batch checkers, compile_source_string() in-memory syntax validation, and DeployValidation with run()/has_errors/print_report() pre-deploy pipeline. Start with the free tier to try compilation patterns and py_compile pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free