Skip to main content

Generates `.pyi` files from Cython modules in a given package directory.

Project description

stubgen-pyx

codecov PyPI - Version CodeFactor Test workflow

Generate Python stub files (.pyi) from Cython source code (.pyx/.pxd)

Automatic stub file generation for Cython extensions that enables full IDE support and type checking for Cython modules.

Table of Contents

Features

Comprehensive Cython Support

  • Extracts type information from Cython source files
  • Preserves docstrings and function signatures
  • Handles both .pyx and .pxd files
  • Supports class hierarchies and inheritance

Smart Processing

  • Automatic import trimming and deduplication
  • Cython type normalization (e.g., bintbool, unicodestr)
  • Proper handling of positional-only and keyword-only arguments
  • Preserves decorators and class metadata

Installation

pip install stubgen-pyx

Quick Start

Generate stubs for all Cython files in the current directory:

stubgen-pyx .

Or use the Python API:

from stubgen_pyx import StubgenPyx
from pathlib import Path

stubgen = StubgenPyx()
results = stubgen.convert_glob("**/*.pyx")

for result in results:
    if result.success:
        print(f"Generated: {result.pyi_file}")
    else:
        print(f"Failed: {result.pyx_file}")
        print(f"  Error: {result.error}")

Usage

Command Line

Basic usage:

# Convert all .pyx files in current directory
stubgen-pyx .

# Convert files in a specific directory
stubgen-pyx /path/to/cython/package

# Use custom glob pattern
stubgen-pyx . --file "**/*.pyx"

Advanced options:

# Write .pyi files to a custom directory
stubgen-pyx . --output-dir stubs/

# Preview changes without writing
stubgen-pyx . --dry-run

# Enable verbose logging
stubgen-pyx . --verbose

# Continue processing even if some files fail
stubgen-pyx . --continue-on-error

# Customize postprocessing
stubgen-pyx . --no-sort-imports --no-trim-imports

Disable specific transformations:

# Disable import sorting
stubgen-pyx . --no-sort-imports

# Don't trim unused imports
stubgen-pyx . --no-trim-imports

# Don't normalize Cython types (keep bint, unicode, etc.)
stubgen-pyx . --no-normalize-names

# Exclude .pxd file contents
stubgen-pyx . --no-pxd-to-stubs

# Skip epilog comment
stubgen-pyx . --exclude-epilog

# Include private functions in the stub
stubgen-pyx . --include-private

Python API

Basic conversion:

from stubgen_pyx import StubgenPyx
from pathlib import Path

stubgen = StubgenPyx()

# Convert a single file
pyx_code = Path("mymodule.pyx").read_text()
pyi_stub = stubgen.convert_str(pyx_code)
print(pyi_stub)

Batch processing with results:

from stubgen_pyx import StubgenPyx

stubgen = StubgenPyx()
results = stubgen.convert_glob("src/**/*.pyx")

successful = sum(1 for r in results if r.success)
failed = sum(1 for r in results if not r.success)

print(f"Converted: {successful}/{len(results)} files")
if failed > 0:
    for result in results:
        if not result.success:
            print(f"  - {result.pyx_file}: {result.error}")

Custom configuration:

from stubgen_pyx import StubgenPyx
from stubgen_pyx.config import StubgenPyxConfig

config = StubgenPyxConfig(
    no_trim_imports=False,      # Trim unused imports
    no_normalize_names=False,   # Normalize Cython types
    no_sort_imports=False,      # Sort imports
    continue_on_error=True,     # Don't stop on first error
    include_private=False,      # Exclude private functions
    verbose=True,               # Detailed output
)

stubgen = StubgenPyx(config=config)
results = stubgen.convert_glob("**/*.pyx")

How It Works

stubgen-pyx works in several stages:

  1. Parsing: Cython source code is parsed using the Cython compiler's AST
  2. Analysis: The AST is visited to extract type information, signatures, and docstrings
  3. Conversion: Cython-specific constructs are converted to intermediate PyiElements
  4. Building: PyiElements are transformed into Python stub code
  5. Postprocessing: Generated code is optimized (imports trimmed, types normalized, etc.)

Why stubgen-pyx vs mypy's stubgen?

While mypy's stubgen can generate stubs for compiled extension modules through runtime introspection, it cannot access Cython-specific metadata embedded in the source code. This results in:

  • Missing type annotations
  • Incomplete function signatures
  • No support for Cython-specific constructs (cdef classes, memory views)

stubgen-pyx directly analyzes the Cython source, providing:

  • Complete type information
  • Accurate function signatures with annotations
  • Preserved docstrings and decorators

Supported Cython Features

Supported

  • Python functions (def)
  • C functions (cdef)
  • C/Python functions (cpdef)
  • Classes (both Python class and Cython cdef class)
  • Class inheritance and metaclasses
  • Type annotations on arguments and return values
  • Docstrings
  • Decorators
  • Default arguments
  • *args and **kwargs
  • Keyword-only arguments
  • Positional-only arguments
  • Cython enums (cdef enum)
  • Import statements (including cimport)
  • Public attributes and properties

Limitations

  • Memory views require manual type hints in some cases
  • Fused types (generics) have basic support

Configuration Options

All configuration is handled through the StubgenPyxConfig dataclass:

Option Type Default Description
no_sort_imports bool False Skip sorting imports
no_trim_imports bool False Skip trimming unused imports
no_pxd_to_stubs bool False Skip including .pxd file contents
no_normalize_names bool False Skip normalizing Cython types to Python equivalents
no_deduplicate_imports bool False Skip deduplicating imports
exclude_epilog bool False Skip adding generation epilog comment
continue_on_error bool False Continue processing even if a file fails
include_private bool False Include private functions in the generated stub
verbose bool False Enable verbose logging output

Example

Input: Cython module

# math_utils.pyx
"""Mathematical utilities for scientific computing."""

cdef class Matrix:
    """A simple matrix class."""

    cdef int rows
    cdef int cols

    def __init__(self, int rows, int cols):
        """Initialize a matrix."""
        self.rows = rows
        self.cols = cols

    def shape(self) -> tuple[int, int]:
        """Get matrix dimensions."""
        return (self.rows, self.cols)

    cpdef scale(self, double factor):
        """Scale all elements."""
        pass

    cdef int _validate(self):
        """Internal validation (not exposed)."""
        return 0

def matrix_product(Matrix a, Matrix b) -> Matrix:
    """Compute matrix product."""
    return Matrix(a.rows, b.cols)

Output: Generated stub

# math_utils.pyi
"""Mathematical utilities for scientific computing."""

from __future__ import annotations

class Matrix:
    """A simple matrix class."""

    def __init__(self, rows: int, cols: int):
        """Initialize a matrix."""

    def shape(self) -> tuple[int, int]:
        """Get matrix dimensions."""

    def scale(self, factor: float):
        """Scale all elements."""

def matrix_product(a: Matrix, b: Matrix) -> Matrix:
    """Compute matrix product."""

# This file was generated by stubgen-pyx v0.x.x from math_utils.pyx

Note:

  • Public methods are included
  • Type annotations are preserved
  • Docstrings are preserved
  • Private cdef method _validate is excluded
  • Private cdef attributes are excluded

Development

Setup

# Clone the repository
git clone https://github.com/jon-edward/stubgen-pyx.git
cd stubgen-pyx

# Create virtual environment
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# Install in development mode with test dependencies
pip install -e ".[test]"

Running Tests

# Run all tests
pytest

# Run specific test file
pytest tests/test_config.py

Project Structure

stubgen-pyx/
├── stubgen_pyx/              # Main package
│   ├── analysis/             # AST analysis (visitors)
│   ├── builders/             # Code generation
│   ├── conversion/           # AST conversion
│   ├── models/               # Data models (PyiElements)
│   ├── parsing/              # Cython parser
│   ├── postprocessing/       # Output optimization
│   ├── cli.py                # Command-line interface
│   ├── config.py             # Configuration
│   └── stubgen.py            # Main entry point
├── tests/                    # Test suite
├── README.md                 # This file
└── pyproject.toml            # Project metadata

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for new functionality
  4. Ensure all tests pass (pytest)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to your fork (git push origin feature/amazing-feature)
  7. Open a Pull Request

License

See LICENSE file for details.

Acknowledgments

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

stubgen_pyx-0.2.3.tar.gz (48.7 kB view details)

Uploaded Source

Built Distribution

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

stubgen_pyx-0.2.3-py3-none-any.whl (33.8 kB view details)

Uploaded Python 3

File details

Details for the file stubgen_pyx-0.2.3.tar.gz.

File metadata

  • Download URL: stubgen_pyx-0.2.3.tar.gz
  • Upload date:
  • Size: 48.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for stubgen_pyx-0.2.3.tar.gz
Algorithm Hash digest
SHA256 3a856a0fbb2608ded8fd1a4b19546b9e785f0b4a1565183b5cf98e33a10a1bff
MD5 3a1e611713dc49d12d60aaf5fc4fd7cf
BLAKE2b-256 c8a67e85ffef8cdf6ecb4f6a006ae2019d3271dd4ea4ebf23b4653a150e812a2

See more details on using hashes here.

File details

Details for the file stubgen_pyx-0.2.3-py3-none-any.whl.

File metadata

  • Download URL: stubgen_pyx-0.2.3-py3-none-any.whl
  • Upload date:
  • Size: 33.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for stubgen_pyx-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 abcdcc247f5fbb8595ebcee730fcbfc6adac5489d0d67152e415e1234d05c609
MD5 6de5b575eb24e7cb5deb49e25455253a
BLAKE2b-256 a2e0adc46f9959657365c8355d839fdc02c38e34a2d0fd70119c0b00e3d23810

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