python-proto-importer


Namepython-proto-importer JSON
Version 0.1.3 PyPI version JSON
download
home_pagehttps://github.com/K-dash/python-proto-importer
SummaryRust-based CLI to streamline Python gRPC/Protobuf workflows
upload_time2025-08-11 03:00:13
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseApache-2.0
keywords protobuf grpc python generator cli
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # python-proto-importer

[![Crates.io](https://img.shields.io/crates/v/python-proto-importer.svg)](https://crates.io/crates/python-proto-importer)
[![PyPI](https://img.shields.io/pypi/v/python-proto-importer.svg)](https://pypi.org/project/python-proto-importer/)
[![CI](https://github.com/K-dash/python-proto-importer/actions/workflows/ci.yml/badge.svg)](https://github.com/K-dash/python-proto-importer/actions)
[![codecov](https://codecov.io/gh/K-dash/python-proto-importer/graph/badge.svg?token=iqNMDrK6Er)](https://codecov.io/gh/K-dash/python-proto-importer)

Rust-based CLI to streamline Python gRPC/Protobuf workflows: generate code, stabilize imports, and run type checks in a single command. Ships as a PyPI package (via maturin) and as a Rust crate.

### Why this project (Motivation)

- **Fragile imports from stock protoc output**: vanilla `grpcio-tools`/`protoc` emit absolute imports (e.g. `import foo.bar_pb2`) that break when you move the generated tree, split packages, or embed code under a different root. This tool rewrites them into stable **relative imports** inside the generated package.
- **Package structure friction**: projects often forget to add `__init__.py` or need namespace packages. We can auto-create `__init__.py` (opt-in/out) to make the tree importable and CI-friendly.
- **Type-checking pain**: mixing generated `.py` and `.pyi` frequently leads to noisy type warnings. We optionally integrate with `mypy-protobuf` / `mypy-grpc`, and recommend `.pyi`-first verification via Pyright.
- **Non-reproducible, multi-step scripts**: teams maintain ad‑hoc scripts for generation, postprocessing, and verification. This CLI runs the full pipeline in one command and stores configuration in `pyproject.toml`.
- **Silent breakages**: generated trees “import” locally but fail in CI or different PYTHONPATHs. A built-in **import dry-run** validates the entire package layout deterministically.

### How it differs from existing tools

- **Postprocess with awareness of your output tree**: relative-import rewriting targets only `_pb2[_grpc]` modules that actually exist beneath your configured `out`, leaving third‑party modules (e.g. `google.protobuf`) untouched by default.
- **Package hygiene by default**: opt-in `__init__.py` generation and path‑robust computation (uses canonical paths) reduce environment‑dependent surprises.
- **Verification built-in**: import dry‑run for all generated modules, plus easy hooks to run `mypy`/`pyright` as part of the same command.
- **Single source of truth in `pyproject.toml`**: keeps your team’s proto generation policy declarative and reviewable.
- **Fast, portable binary**: implemented in Rust with a small runtime footprint; distributed both on PyPI (wheel) and crates.io.

- **Backends**: `protoc` (v0.1), `buf generate` (planned v0.2)
- **Postprocess**: convert internal imports to relative; generate `__init__.py`
- **Typing**: optional `mypy-protobuf` / `mypy-grpc` emission
- **Verification**: import dry-run, optional mypy/pyright

For Japanese documentation, see: [docs/日本語 README](doc/README.ja.md)

## Table of Contents

- [Quick Start](#quick-start)
- [Commands](#commands)
- [Configuration](#configuration)
  - [Core Configuration](#core-configuration)
  - [Postprocess Configuration](#postprocess-configuration)
  - [Verification Configuration](#verification-configuration)
- [Configuration Examples](#configuration-examples)
- [Advanced Usage](#advanced-usage)
- [Limitations](#limitations)
- [Contributing](#contributing)
- [License](#license)

## Quick Start

```bash
pip install python-proto-importer
# or
cargo install python-proto-importer
```

Create a `pyproject.toml` with your configuration:

```toml
[tool.python_proto_importer]
backend = "protoc"
python_exe = "python3"
include = ["proto"]
inputs = ["proto/**/*.proto"]
out = "generated/python"
```

Run the build:

```bash
proto-importer build
```

## Commands

### `proto-importer doctor`

Environment diagnostics with versions and helpful hints:

- Detects Python runner (uv/python) and shows versions
- Checks for `grpcio-tools` (required), `mypy-protobuf` / `mypy-grpc` (optional per config)
- Shows `protoc` / `buf` versions (informational in v0.1)
- Checks `mypy` / `pyright` CLIs and prints hints if configured but missing

### `proto-importer build [--pyproject PATH]`

Generate Python code from proto files, apply postprocessing, and run verification.

Options:

- `--pyproject PATH`: Path to pyproject.toml (default: `./pyproject.toml`)
- `--no-verify`: Skip verification after generation
- `--postprocess-only`: Skip generation, only run postprocessing (experimental)

### `proto-importer check [--pyproject PATH]`

Run verification only (import dry-run and type checks) without generation.

### `proto-importer clean [--pyproject PATH] --yes`

Remove generated output directory. Requires `--yes` confirmation.

## Configuration

All configuration is done through `pyproject.toml` under the `[tool.python_proto_importer]` section.

### Core Configuration

| Option       | Type    | Default              | Description                                                                                                                                                |
| ------------ | ------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `backend`    | string  | `"protoc"`           | Code generation backend. Currently only `"protoc"` is supported. `"buf"` planned for v0.2.                                                                 |
| `python_exe` | string  | `"python3"`          | Python executable to use for generation and verification. Can be `"python3"`, `"python"`, `"uv"` (fully tested), or a path like `".venv/bin/python"`.      |
| `include`    | array   | `["."]`              | Proto import paths (passed as `--proto_path` to protoc). Empty array defaults to `["."]`. See [Include Path Behavior](#include-path-behavior) for details. |
| `inputs`     | array   | `[]`                 | Glob patterns for proto files to generate. Example: `["proto/**/*.proto"]`. Files are filtered by `include` paths.                                         |
| `out`        | string  | `"generated/python"` | Output directory for generated Python files.                                                                                                               |
| `mypy`       | boolean | `false`              | Generate mypy type stubs (`.pyi` files) using `mypy-protobuf`.                                                                                             |
| `mypy_grpc`  | boolean | `false`              | Generate gRPC mypy stubs (`_grpc.pyi` files) using `mypy-grpc`.                                                                                            |

#### Include Path Behavior

The `include` option controls proto import paths and has important interactions with `inputs`:

1. **Default Behavior**: If `include` is empty or not specified, it defaults to `["."]` (current directory).

2. **Path Resolution**: Each path in `include` is passed to protoc as `--proto_path`. Proto files can only import other protos within these paths.

3. **Input Filtering**: Files matched by `inputs` globs are automatically filtered to only include those under `include` paths. This prevents protoc errors when globs match files outside the include paths.

4. **Output Structure**: Generated files maintain the directory structure relative to the `include` path. For example:

   - With `include = ["proto"]` and a file at `proto/service/api.proto`
   - Output will be at `{out}/service/api_pb2.py`

5. **Multiple Include Paths**: When specifying multiple paths like `include = ["proto/common", "proto/services"]`, be aware that files with the same relative path may cause conflicts.

**Examples:**

```toml
# Simple case - all protos under proto/ directory
include = ["proto"]
inputs = ["proto/**/*.proto"]

# Multiple include paths - useful for separate proto roots
include = ["common/proto", "services/proto"]
inputs = ["**/*.proto"]

# Selective generation - only specific services
include = ["."]  # Use current directory to avoid path conflicts
inputs = ["proto/payment/**/*.proto", "proto/user/**/*.proto"]

# Alternative proto structure
include = ["api/definitions"]
inputs = ["api/definitions/**/*.proto"]
```

### Postprocess Configuration

The `postprocess` table controls post-generation transformations:

| Option             | Type    | Default   | Description                                                                                     |
| ------------------ | ------- | --------- | ----------------------------------------------------------------------------------------------- |
| `relative_imports` | boolean | `true`    | Convert absolute imports to relative imports within generated files.                            |
| `fix_pyi`          | boolean | `true`    | Fix type annotations in `.pyi` files (currently reserved for future use).                       |
| `create_package`   | boolean | `true`    | Create `__init__.py` files in all directories. Set to `false` for namespace packages (PEP 420). |
| `exclude_google`   | boolean | `true`    | Exclude `google.protobuf` imports from relative import conversion.                              |
| `pyright_header`   | boolean | `false`   | Add Pyright suppression header to generated `_pb2.py` and `_pb2_grpc.py` files.                 |
| `module_suffixes`  | array   | See below | File suffixes to process during postprocessing.                                                 |

Default `module_suffixes`:

```toml
module_suffixes = ["_pb2.py", "_pb2.pyi", "_pb2_grpc.py", "_pb2_grpc.pyi"]
```

#### Import Rewrite Coverage and Limitations

- Covered patterns:
  - `import pkg.module_pb2` / `import pkg.module_pb2 as alias`
  - `import pkg.mod1_pb2, pkg.sub.mod2_pb2 as alias` (split into multiple `from` lines)
  - `from pkg import module_pb2` / `from pkg import module_pb2 as alias`
  - `from pkg import mod1_pb2, mod2_pb2 as alias`
  - `from pkg import (\n    mod1_pb2,\n    mod2_pb2 as alias,\n  )`
- Exclusions/known behaviors:
  - `google.protobuf.*` is excluded when `exclude_google = true` (default).
  - Parentheses-based line continuation is supported for `from ... import (...)`; backslash continuations (e.g. `\\`) are not currently handled.
  - Only modules matching `_pb2` / `_pb2_grpc` are candidates; other imports are left unchanged.
  - Mixed lists are split: rewritten items go to a relative `from` line; non-target items remain as their original import.
  - Rewrites only apply if the target module file exists under the configured `out` tree.

#### Path Resolution Robustness

- The tool computes relative import prefixes using canonicalized paths (`realpath`),
  which reduces inconsistencies from relative segments (e.g., `./`, `../`) and
  symlinks. If canonicalization fails (non-existent paths, permission), it falls
  back to a best-effort relative computation.
- Practical tip: ensure your generated tree exists before postprocessing so the
  canonicalization can establish a stable common prefix.

### Verification Configuration

The `[tool.python_proto_importer.verify]` section configures optional verification commands:

| Option        | Type  | Default | Description                                                                     |
| ------------- | ----- | ------- | ------------------------------------------------------------------------------- |
| `mypy_cmd`    | array | `null`  | Command to run mypy type checking. Example: `["mypy", "--strict", "generated"]` |
| `pyright_cmd` | array | `null`  | Command to run pyright type checking. Example: `["pyright", "generated"]`       |

**Important Notes:**

1. **Import Dry-run**: Always performed automatically. The tool attempts to import all generated Python modules to ensure they're valid.

2. **Type Checking**: Only runs if configured. The tools (mypy/pyright) must be available in your environment.

3. **Command Arrays**: Commands are specified as arrays where the first element is the executable and remaining elements are arguments.

**Examples:**

```toml
[tool.python_proto_importer.verify]
# Using uv to run type checkers
mypy_cmd = ["uv", "run", "mypy", "--strict", "generated/python"]
pyright_cmd = ["uv", "run", "pyright", "generated/python"]

# Direct execution
mypy_cmd = ["mypy", "--config-file", "mypy.ini", "generated"]

# Check only .pyi files with pyright
pyright_cmd = ["pyright", "generated/**/*.pyi"]

# Exclude generated gRPC files from mypy strict checking
mypy_cmd = ["mypy", "--strict", "--exclude", ".*_grpc\\.py$", "generated"]
```

## Configuration Examples

### Minimal Configuration

```toml
[tool.python_proto_importer]
backend = "protoc"
inputs = ["proto/**/*.proto"]
out = "generated"
```

### Full-Featured Configuration

```toml
[tool.python_proto_importer]
backend = "protoc"
python_exe = ".venv/bin/python"
include = ["proto"]
inputs = ["proto/**/*.proto"]
out = "src/generated"
mypy = true
mypy_grpc = true

[tool.python_proto_importer.postprocess]
relative_imports = true
fix_pyi = true
create_package = true
exclude_google = true
pyright_header = true

[tool.python_proto_importer.verify]
mypy_cmd = ["uv", "run", "mypy", "--strict", "--exclude", ".*_grpc\\.py$", "src/generated"]
pyright_cmd = ["uv", "run", "pyright", "src/generated/**/*.pyi"]
```

Note: For pyright, we recommend focusing on `.pyi` stubs (as shown) to avoid warnings from generated `.py` that intentionally reference experimental or dynamically provided attributes.

### Pyi-only Verification Example

```toml
[tool.python_proto_importer]
backend = "protoc"
include = ["proto"]
inputs = ["proto/**/*.proto"]
out = "generated/python"
mypy = true

[tool.python_proto_importer.verify]
# Validate only the generated stubs with pyright
pyright_cmd = ["uv", "run", "pyright", "generated/python/**/*.pyi"]
```

### Namespace Package Configuration (PEP 420)

```toml
[tool.python_proto_importer]
backend = "protoc"
include = ["proto"]
inputs = ["proto/**/*.proto"]
out = "generated"

[tool.python_proto_importer.postprocess]
create_package = false  # Don't create __init__.py files
```

### Selective Service Generation

```toml
[tool.python_proto_importer]
backend = "protoc"
include = ["."]
# Only generate specific services
inputs = [
    "proto/authentication/**/*.proto",
    "proto/user_management/**/*.proto"
]
out = "services/generated"
```

### Custom Directory Structure

```toml
[tool.python_proto_importer]
backend = "protoc"
# For non-standard proto locations
include = ["api/v1/definitions"]
inputs = ["api/v1/definitions/**/*.proto"]
out = "build/python/api"
```

## Advanced Usage

### Using with uv

[uv](https://github.com/astral-sh/uv) is a fast Python package manager that can replace pip and virtualenv:

```toml
[tool.python_proto_importer]
python_exe = "uv"  # or ".venv/bin/python" if using uv venv
# ... rest of config

[tool.python_proto_importer.verify]
mypy_cmd = ["uv", "run", "mypy", "--strict", "generated"]
```

### CI/CD Integration

```yaml
# GitHub Actions example
- name: Install dependencies
  run: |
    pip install python-proto-importer
    pip install grpcio-tools mypy-protobuf

- name: Generate Python code from protos
  run: proto-importer build

- name: Run tests
  run: pytest tests/
```

### Understanding `include` vs `inputs`

One of the most important concepts to understand when configuring python-proto-importer is the difference between `include` and `inputs`:

#### 🗂️ `include` - "Where to Look" (Search Paths)

Specifies **where** the protobuf compiler (protoc) should **search** for `.proto` files.

#### 📄 `inputs` - "What to Compile" (Target Files)

Specifies **which** `.proto` files you want to **compile** using glob patterns.

#### 🏗️ Example Project Structure

```
my-project/
├── api/
│   ├── user/
│   │   └── user.proto          # Want to compile this
│   └── order/
│       └── order.proto         # Want to compile this
├── third_party/
│   └── google/
│       └── protobuf/
│           └── timestamp.proto # Referenced as dependency
└── generated/                  # Output directory
```

#### ⚙️ Configuration Example

```toml
[tool.python_proto_importer]
include = ["api", "third_party"]           # Search paths
inputs = ["api/**/*.proto"]                # Files to compile
out = "generated"
```

#### 🔍 How It Works

1. **`inputs`**: `api/**/*.proto` → finds `user.proto` and `order.proto`
2. **`include`**: Sets `api` and `third_party` as search paths
3. **Compilation**:
   - When compiling `user.proto`, if it contains `import "google/protobuf/timestamp.proto"`
   - The compiler can automatically find `third_party/google/protobuf/timestamp.proto`

#### 🚫 Common Mistakes

**❌ Wrong Pattern:**

```toml
# Wrong: Including dependencies in inputs causes them to be generated
inputs = ["api/**/*.proto", "third_party/**/*.proto"]  # Generates unwanted files
include = ["api"]                                      # Missing search paths
```

**✅ Correct Pattern:**

```toml
# Correct: Only compile what you need, but include all search paths
inputs = ["api/**/*.proto"]                    # Only compile your API files
include = ["api", "third_party"]               # Include all paths for dependencies
```

#### 🎯 Key Takeaway

- **`include`** = Compiler's "eyes" (what it can see)
- **`inputs`** = Compiler's "hands" (what it grabs and compiles)

Dependencies are **not compiled** (excluded from `inputs`) but **must be searchable** (included in `include`).

This approach ensures you **generate only the files you need** while **properly resolving all dependencies**.

### Handling Complex Proto Dependencies

When dealing with complex proto dependencies across multiple directories:

```toml
[tool.python_proto_importer]
# Include all necessary proto roots
include = [
    ".",
    "third_party/proto",
    "vendor/proto"
]
# Use specific patterns to avoid conflicts
inputs = [
    "src/proto/**/*.proto",
    "third_party/proto/specific_service/**/*.proto"
]
out = "generated"
```

## Limitations

- **v0.1 limitations**:
  - Only `protoc` backend is supported. `buf generate` support is planned for v0.2.
  - Import rewriting targets common `_pb2(_grpc)?.py[i]` patterns; broader coverage is added incrementally with tests.
  - Import dry-run verifies only generated `.py` modules (excluding `__init__.py`). `.pyi` files are not imported and should be validated via type checkers (e.g., configure `pyright_cmd` to point at `**/*.pyi`).
  - The `fix_pyi` flag is reserved for future use in v0.1 and currently has no effect.
- **Known behaviors**:
  - When using multiple `include` paths with files of the same name, protoc may report "shadowing" errors. Use selective `inputs` patterns to avoid this.
  - Generated file structure follows protoc conventions: files are placed relative to their `--proto_path`.
  - Type checkers (mypy/pyright) must be installed separately and available in PATH or the Python environment.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.

## License

Apache-2.0. See LICENSE for details.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/K-dash/python-proto-importer",
    "name": "python-proto-importer",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "protobuf, grpc, python, generator, cli",
    "author": null,
    "author_email": "K-dash <maintainers+python-proto-importer@kdash.dev>",
    "download_url": "https://files.pythonhosted.org/packages/20/7e/9a7d3e0aec3136ba8b0c34be6dd3a908d16756ea6b3dd4934828aca8513b/python_proto_importer-0.1.3.tar.gz",
    "platform": null,
    "description": "# python-proto-importer\n\n[![Crates.io](https://img.shields.io/crates/v/python-proto-importer.svg)](https://crates.io/crates/python-proto-importer)\n[![PyPI](https://img.shields.io/pypi/v/python-proto-importer.svg)](https://pypi.org/project/python-proto-importer/)\n[![CI](https://github.com/K-dash/python-proto-importer/actions/workflows/ci.yml/badge.svg)](https://github.com/K-dash/python-proto-importer/actions)\n[![codecov](https://codecov.io/gh/K-dash/python-proto-importer/graph/badge.svg?token=iqNMDrK6Er)](https://codecov.io/gh/K-dash/python-proto-importer)\n\nRust-based CLI to streamline Python gRPC/Protobuf workflows: generate code, stabilize imports, and run type checks in a single command. Ships as a PyPI package (via maturin) and as a Rust crate.\n\n### Why this project (Motivation)\n\n- **Fragile imports from stock protoc output**: vanilla `grpcio-tools`/`protoc` emit absolute imports (e.g. `import foo.bar_pb2`) that break when you move the generated tree, split packages, or embed code under a different root. This tool rewrites them into stable **relative imports** inside the generated package.\n- **Package structure friction**: projects often forget to add `__init__.py` or need namespace packages. We can auto-create `__init__.py` (opt-in/out) to make the tree importable and CI-friendly.\n- **Type-checking pain**: mixing generated `.py` and `.pyi` frequently leads to noisy type warnings. We optionally integrate with `mypy-protobuf` / `mypy-grpc`, and recommend `.pyi`-first verification via Pyright.\n- **Non-reproducible, multi-step scripts**: teams maintain ad\u2011hoc scripts for generation, postprocessing, and verification. This CLI runs the full pipeline in one command and stores configuration in `pyproject.toml`.\n- **Silent breakages**: generated trees \u201cimport\u201d locally but fail in CI or different PYTHONPATHs. A built-in **import dry-run** validates the entire package layout deterministically.\n\n### How it differs from existing tools\n\n- **Postprocess with awareness of your output tree**: relative-import rewriting targets only `_pb2[_grpc]` modules that actually exist beneath your configured `out`, leaving third\u2011party modules (e.g. `google.protobuf`) untouched by default.\n- **Package hygiene by default**: opt-in `__init__.py` generation and path\u2011robust computation (uses canonical paths) reduce environment\u2011dependent surprises.\n- **Verification built-in**: import dry\u2011run for all generated modules, plus easy hooks to run `mypy`/`pyright` as part of the same command.\n- **Single source of truth in `pyproject.toml`**: keeps your team\u2019s proto generation policy declarative and reviewable.\n- **Fast, portable binary**: implemented in Rust with a small runtime footprint; distributed both on PyPI (wheel) and crates.io.\n\n- **Backends**: `protoc` (v0.1), `buf generate` (planned v0.2)\n- **Postprocess**: convert internal imports to relative; generate `__init__.py`\n- **Typing**: optional `mypy-protobuf` / `mypy-grpc` emission\n- **Verification**: import dry-run, optional mypy/pyright\n\nFor Japanese documentation, see: [docs/\u65e5\u672c\u8a9e README](doc/README.ja.md)\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Commands](#commands)\n- [Configuration](#configuration)\n  - [Core Configuration](#core-configuration)\n  - [Postprocess Configuration](#postprocess-configuration)\n  - [Verification Configuration](#verification-configuration)\n- [Configuration Examples](#configuration-examples)\n- [Advanced Usage](#advanced-usage)\n- [Limitations](#limitations)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Quick Start\n\n```bash\npip install python-proto-importer\n# or\ncargo install python-proto-importer\n```\n\nCreate a `pyproject.toml` with your configuration:\n\n```toml\n[tool.python_proto_importer]\nbackend = \"protoc\"\npython_exe = \"python3\"\ninclude = [\"proto\"]\ninputs = [\"proto/**/*.proto\"]\nout = \"generated/python\"\n```\n\nRun the build:\n\n```bash\nproto-importer build\n```\n\n## Commands\n\n### `proto-importer doctor`\n\nEnvironment diagnostics with versions and helpful hints:\n\n- Detects Python runner (uv/python) and shows versions\n- Checks for `grpcio-tools` (required), `mypy-protobuf` / `mypy-grpc` (optional per config)\n- Shows `protoc` / `buf` versions (informational in v0.1)\n- Checks `mypy` / `pyright` CLIs and prints hints if configured but missing\n\n### `proto-importer build [--pyproject PATH]`\n\nGenerate Python code from proto files, apply postprocessing, and run verification.\n\nOptions:\n\n- `--pyproject PATH`: Path to pyproject.toml (default: `./pyproject.toml`)\n- `--no-verify`: Skip verification after generation\n- `--postprocess-only`: Skip generation, only run postprocessing (experimental)\n\n### `proto-importer check [--pyproject PATH]`\n\nRun verification only (import dry-run and type checks) without generation.\n\n### `proto-importer clean [--pyproject PATH] --yes`\n\nRemove generated output directory. Requires `--yes` confirmation.\n\n## Configuration\n\nAll configuration is done through `pyproject.toml` under the `[tool.python_proto_importer]` section.\n\n### Core Configuration\n\n| Option       | Type    | Default              | Description                                                                                                                                                |\n| ------------ | ------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `backend`    | string  | `\"protoc\"`           | Code generation backend. Currently only `\"protoc\"` is supported. `\"buf\"` planned for v0.2.                                                                 |\n| `python_exe` | string  | `\"python3\"`          | Python executable to use for generation and verification. Can be `\"python3\"`, `\"python\"`, `\"uv\"` (fully tested), or a path like `\".venv/bin/python\"`.      |\n| `include`    | array   | `[\".\"]`              | Proto import paths (passed as `--proto_path` to protoc). Empty array defaults to `[\".\"]`. See [Include Path Behavior](#include-path-behavior) for details. |\n| `inputs`     | array   | `[]`                 | Glob patterns for proto files to generate. Example: `[\"proto/**/*.proto\"]`. Files are filtered by `include` paths.                                         |\n| `out`        | string  | `\"generated/python\"` | Output directory for generated Python files.                                                                                                               |\n| `mypy`       | boolean | `false`              | Generate mypy type stubs (`.pyi` files) using `mypy-protobuf`.                                                                                             |\n| `mypy_grpc`  | boolean | `false`              | Generate gRPC mypy stubs (`_grpc.pyi` files) using `mypy-grpc`.                                                                                            |\n\n#### Include Path Behavior\n\nThe `include` option controls proto import paths and has important interactions with `inputs`:\n\n1. **Default Behavior**: If `include` is empty or not specified, it defaults to `[\".\"]` (current directory).\n\n2. **Path Resolution**: Each path in `include` is passed to protoc as `--proto_path`. Proto files can only import other protos within these paths.\n\n3. **Input Filtering**: Files matched by `inputs` globs are automatically filtered to only include those under `include` paths. This prevents protoc errors when globs match files outside the include paths.\n\n4. **Output Structure**: Generated files maintain the directory structure relative to the `include` path. For example:\n\n   - With `include = [\"proto\"]` and a file at `proto/service/api.proto`\n   - Output will be at `{out}/service/api_pb2.py`\n\n5. **Multiple Include Paths**: When specifying multiple paths like `include = [\"proto/common\", \"proto/services\"]`, be aware that files with the same relative path may cause conflicts.\n\n**Examples:**\n\n```toml\n# Simple case - all protos under proto/ directory\ninclude = [\"proto\"]\ninputs = [\"proto/**/*.proto\"]\n\n# Multiple include paths - useful for separate proto roots\ninclude = [\"common/proto\", \"services/proto\"]\ninputs = [\"**/*.proto\"]\n\n# Selective generation - only specific services\ninclude = [\".\"]  # Use current directory to avoid path conflicts\ninputs = [\"proto/payment/**/*.proto\", \"proto/user/**/*.proto\"]\n\n# Alternative proto structure\ninclude = [\"api/definitions\"]\ninputs = [\"api/definitions/**/*.proto\"]\n```\n\n### Postprocess Configuration\n\nThe `postprocess` table controls post-generation transformations:\n\n| Option             | Type    | Default   | Description                                                                                     |\n| ------------------ | ------- | --------- | ----------------------------------------------------------------------------------------------- |\n| `relative_imports` | boolean | `true`    | Convert absolute imports to relative imports within generated files.                            |\n| `fix_pyi`          | boolean | `true`    | Fix type annotations in `.pyi` files (currently reserved for future use).                       |\n| `create_package`   | boolean | `true`    | Create `__init__.py` files in all directories. Set to `false` for namespace packages (PEP 420). |\n| `exclude_google`   | boolean | `true`    | Exclude `google.protobuf` imports from relative import conversion.                              |\n| `pyright_header`   | boolean | `false`   | Add Pyright suppression header to generated `_pb2.py` and `_pb2_grpc.py` files.                 |\n| `module_suffixes`  | array   | See below | File suffixes to process during postprocessing.                                                 |\n\nDefault `module_suffixes`:\n\n```toml\nmodule_suffixes = [\"_pb2.py\", \"_pb2.pyi\", \"_pb2_grpc.py\", \"_pb2_grpc.pyi\"]\n```\n\n#### Import Rewrite Coverage and Limitations\n\n- Covered patterns:\n  - `import pkg.module_pb2` / `import pkg.module_pb2 as alias`\n  - `import pkg.mod1_pb2, pkg.sub.mod2_pb2 as alias` (split into multiple `from` lines)\n  - `from pkg import module_pb2` / `from pkg import module_pb2 as alias`\n  - `from pkg import mod1_pb2, mod2_pb2 as alias`\n  - `from pkg import (\\n    mod1_pb2,\\n    mod2_pb2 as alias,\\n  )`\n- Exclusions/known behaviors:\n  - `google.protobuf.*` is excluded when `exclude_google = true` (default).\n  - Parentheses-based line continuation is supported for `from ... import (...)`; backslash continuations (e.g. `\\\\`) are not currently handled.\n  - Only modules matching `_pb2` / `_pb2_grpc` are candidates; other imports are left unchanged.\n  - Mixed lists are split: rewritten items go to a relative `from` line; non-target items remain as their original import.\n  - Rewrites only apply if the target module file exists under the configured `out` tree.\n\n#### Path Resolution Robustness\n\n- The tool computes relative import prefixes using canonicalized paths (`realpath`),\n  which reduces inconsistencies from relative segments (e.g., `./`, `../`) and\n  symlinks. If canonicalization fails (non-existent paths, permission), it falls\n  back to a best-effort relative computation.\n- Practical tip: ensure your generated tree exists before postprocessing so the\n  canonicalization can establish a stable common prefix.\n\n### Verification Configuration\n\nThe `[tool.python_proto_importer.verify]` section configures optional verification commands:\n\n| Option        | Type  | Default | Description                                                                     |\n| ------------- | ----- | ------- | ------------------------------------------------------------------------------- |\n| `mypy_cmd`    | array | `null`  | Command to run mypy type checking. Example: `[\"mypy\", \"--strict\", \"generated\"]` |\n| `pyright_cmd` | array | `null`  | Command to run pyright type checking. Example: `[\"pyright\", \"generated\"]`       |\n\n**Important Notes:**\n\n1. **Import Dry-run**: Always performed automatically. The tool attempts to import all generated Python modules to ensure they're valid.\n\n2. **Type Checking**: Only runs if configured. The tools (mypy/pyright) must be available in your environment.\n\n3. **Command Arrays**: Commands are specified as arrays where the first element is the executable and remaining elements are arguments.\n\n**Examples:**\n\n```toml\n[tool.python_proto_importer.verify]\n# Using uv to run type checkers\nmypy_cmd = [\"uv\", \"run\", \"mypy\", \"--strict\", \"generated/python\"]\npyright_cmd = [\"uv\", \"run\", \"pyright\", \"generated/python\"]\n\n# Direct execution\nmypy_cmd = [\"mypy\", \"--config-file\", \"mypy.ini\", \"generated\"]\n\n# Check only .pyi files with pyright\npyright_cmd = [\"pyright\", \"generated/**/*.pyi\"]\n\n# Exclude generated gRPC files from mypy strict checking\nmypy_cmd = [\"mypy\", \"--strict\", \"--exclude\", \".*_grpc\\\\.py$\", \"generated\"]\n```\n\n## Configuration Examples\n\n### Minimal Configuration\n\n```toml\n[tool.python_proto_importer]\nbackend = \"protoc\"\ninputs = [\"proto/**/*.proto\"]\nout = \"generated\"\n```\n\n### Full-Featured Configuration\n\n```toml\n[tool.python_proto_importer]\nbackend = \"protoc\"\npython_exe = \".venv/bin/python\"\ninclude = [\"proto\"]\ninputs = [\"proto/**/*.proto\"]\nout = \"src/generated\"\nmypy = true\nmypy_grpc = true\n\n[tool.python_proto_importer.postprocess]\nrelative_imports = true\nfix_pyi = true\ncreate_package = true\nexclude_google = true\npyright_header = true\n\n[tool.python_proto_importer.verify]\nmypy_cmd = [\"uv\", \"run\", \"mypy\", \"--strict\", \"--exclude\", \".*_grpc\\\\.py$\", \"src/generated\"]\npyright_cmd = [\"uv\", \"run\", \"pyright\", \"src/generated/**/*.pyi\"]\n```\n\nNote: For pyright, we recommend focusing on `.pyi` stubs (as shown) to avoid warnings from generated `.py` that intentionally reference experimental or dynamically provided attributes.\n\n### Pyi-only Verification Example\n\n```toml\n[tool.python_proto_importer]\nbackend = \"protoc\"\ninclude = [\"proto\"]\ninputs = [\"proto/**/*.proto\"]\nout = \"generated/python\"\nmypy = true\n\n[tool.python_proto_importer.verify]\n# Validate only the generated stubs with pyright\npyright_cmd = [\"uv\", \"run\", \"pyright\", \"generated/python/**/*.pyi\"]\n```\n\n### Namespace Package Configuration (PEP 420)\n\n```toml\n[tool.python_proto_importer]\nbackend = \"protoc\"\ninclude = [\"proto\"]\ninputs = [\"proto/**/*.proto\"]\nout = \"generated\"\n\n[tool.python_proto_importer.postprocess]\ncreate_package = false  # Don't create __init__.py files\n```\n\n### Selective Service Generation\n\n```toml\n[tool.python_proto_importer]\nbackend = \"protoc\"\ninclude = [\".\"]\n# Only generate specific services\ninputs = [\n    \"proto/authentication/**/*.proto\",\n    \"proto/user_management/**/*.proto\"\n]\nout = \"services/generated\"\n```\n\n### Custom Directory Structure\n\n```toml\n[tool.python_proto_importer]\nbackend = \"protoc\"\n# For non-standard proto locations\ninclude = [\"api/v1/definitions\"]\ninputs = [\"api/v1/definitions/**/*.proto\"]\nout = \"build/python/api\"\n```\n\n## Advanced Usage\n\n### Using with uv\n\n[uv](https://github.com/astral-sh/uv) is a fast Python package manager that can replace pip and virtualenv:\n\n```toml\n[tool.python_proto_importer]\npython_exe = \"uv\"  # or \".venv/bin/python\" if using uv venv\n# ... rest of config\n\n[tool.python_proto_importer.verify]\nmypy_cmd = [\"uv\", \"run\", \"mypy\", \"--strict\", \"generated\"]\n```\n\n### CI/CD Integration\n\n```yaml\n# GitHub Actions example\n- name: Install dependencies\n  run: |\n    pip install python-proto-importer\n    pip install grpcio-tools mypy-protobuf\n\n- name: Generate Python code from protos\n  run: proto-importer build\n\n- name: Run tests\n  run: pytest tests/\n```\n\n### Understanding `include` vs `inputs`\n\nOne of the most important concepts to understand when configuring python-proto-importer is the difference between `include` and `inputs`:\n\n#### \ud83d\uddc2\ufe0f `include` - \"Where to Look\" (Search Paths)\n\nSpecifies **where** the protobuf compiler (protoc) should **search** for `.proto` files.\n\n#### \ud83d\udcc4 `inputs` - \"What to Compile\" (Target Files)\n\nSpecifies **which** `.proto` files you want to **compile** using glob patterns.\n\n#### \ud83c\udfd7\ufe0f Example Project Structure\n\n```\nmy-project/\n\u251c\u2500\u2500 api/\n\u2502   \u251c\u2500\u2500 user/\n\u2502   \u2502   \u2514\u2500\u2500 user.proto          # Want to compile this\n\u2502   \u2514\u2500\u2500 order/\n\u2502       \u2514\u2500\u2500 order.proto         # Want to compile this\n\u251c\u2500\u2500 third_party/\n\u2502   \u2514\u2500\u2500 google/\n\u2502       \u2514\u2500\u2500 protobuf/\n\u2502           \u2514\u2500\u2500 timestamp.proto # Referenced as dependency\n\u2514\u2500\u2500 generated/                  # Output directory\n```\n\n#### \u2699\ufe0f Configuration Example\n\n```toml\n[tool.python_proto_importer]\ninclude = [\"api\", \"third_party\"]           # Search paths\ninputs = [\"api/**/*.proto\"]                # Files to compile\nout = \"generated\"\n```\n\n#### \ud83d\udd0d How It Works\n\n1. **`inputs`**: `api/**/*.proto` \u2192 finds `user.proto` and `order.proto`\n2. **`include`**: Sets `api` and `third_party` as search paths\n3. **Compilation**:\n   - When compiling `user.proto`, if it contains `import \"google/protobuf/timestamp.proto\"`\n   - The compiler can automatically find `third_party/google/protobuf/timestamp.proto`\n\n#### \ud83d\udeab Common Mistakes\n\n**\u274c Wrong Pattern:**\n\n```toml\n# Wrong: Including dependencies in inputs causes them to be generated\ninputs = [\"api/**/*.proto\", \"third_party/**/*.proto\"]  # Generates unwanted files\ninclude = [\"api\"]                                      # Missing search paths\n```\n\n**\u2705 Correct Pattern:**\n\n```toml\n# Correct: Only compile what you need, but include all search paths\ninputs = [\"api/**/*.proto\"]                    # Only compile your API files\ninclude = [\"api\", \"third_party\"]               # Include all paths for dependencies\n```\n\n#### \ud83c\udfaf Key Takeaway\n\n- **`include`** = Compiler's \"eyes\" (what it can see)\n- **`inputs`** = Compiler's \"hands\" (what it grabs and compiles)\n\nDependencies are **not compiled** (excluded from `inputs`) but **must be searchable** (included in `include`).\n\nThis approach ensures you **generate only the files you need** while **properly resolving all dependencies**.\n\n### Handling Complex Proto Dependencies\n\nWhen dealing with complex proto dependencies across multiple directories:\n\n```toml\n[tool.python_proto_importer]\n# Include all necessary proto roots\ninclude = [\n    \".\",\n    \"third_party/proto\",\n    \"vendor/proto\"\n]\n# Use specific patterns to avoid conflicts\ninputs = [\n    \"src/proto/**/*.proto\",\n    \"third_party/proto/specific_service/**/*.proto\"\n]\nout = \"generated\"\n```\n\n## Limitations\n\n- **v0.1 limitations**:\n  - Only `protoc` backend is supported. `buf generate` support is planned for v0.2.\n  - Import rewriting targets common `_pb2(_grpc)?.py[i]` patterns; broader coverage is added incrementally with tests.\n  - Import dry-run verifies only generated `.py` modules (excluding `__init__.py`). `.pyi` files are not imported and should be validated via type checkers (e.g., configure `pyright_cmd` to point at `**/*.pyi`).\n  - The `fix_pyi` flag is reserved for future use in v0.1 and currently has no effect.\n- **Known behaviors**:\n  - When using multiple `include` paths with files of the same name, protoc may report \"shadowing\" errors. Use selective `inputs` patterns to avoid this.\n  - Generated file structure follows protoc conventions: files are placed relative to their `--proto_path`.\n  - Type checkers (mypy/pyright) must be installed separately and available in PATH or the Python environment.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.\n\n## License\n\nApache-2.0. See LICENSE for details.\n\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Rust-based CLI to streamline Python gRPC/Protobuf workflows",
    "version": "0.1.3",
    "project_urls": {
        "Homepage": "https://github.com/K-dash/python-proto-importer",
        "Repository": "https://github.com/K-dash/python-proto-importer"
    },
    "split_keywords": [
        "protobuf",
        " grpc",
        " python",
        " generator",
        " cli"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "85be7b74e93b8e84c596684b990f05276516755dc02f1dac109fc367720e7466",
                "md5": "b4225da81f69a63367d497a2b3a9d529",
                "sha256": "b7aeaac822faa467edba1f7992ef295b6dff817ec006fe6259d048d6fb95bb5f"
            },
            "downloads": -1,
            "filename": "python_proto_importer-0.1.3-cp38-abi3-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "b4225da81f69a63367d497a2b3a9d529",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.11",
            "size": 2074558,
            "upload_time": "2025-08-11T02:59:05",
            "upload_time_iso_8601": "2025-08-11T02:59:05.540247Z",
            "url": "https://files.pythonhosted.org/packages/85/be/7b74e93b8e84c596684b990f05276516755dc02f1dac109fc367720e7466/python_proto_importer-0.1.3-cp38-abi3-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "3dc28f64649a871c018bb3ae011617c8c8a0e19897dd97cacbed4d1635e5c617",
                "md5": "aa3084d7745c665fb83f4ab3391de8ee",
                "sha256": "1a2724361637d44bea31c4e17c79b282b57feeb8290ac97eab46870f15fd272f"
            },
            "downloads": -1,
            "filename": "python_proto_importer-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "aa3084d7745c665fb83f4ab3391de8ee",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.11",
            "size": 2418417,
            "upload_time": "2025-08-11T03:00:11",
            "upload_time_iso_8601": "2025-08-11T03:00:11.517162Z",
            "url": "https://files.pythonhosted.org/packages/3d/c2/8f64649a871c018bb3ae011617c8c8a0e19897dd97cacbed4d1635e5c617/python_proto_importer-0.1.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "72e82cbd2e09f62fc274b31079db7a0715adad7801366c41b952313b2b37d68c",
                "md5": "9a801a6f08383dcfb2b73eeb10ab0924",
                "sha256": "33d750994135b7b2c20f0b585a4ef21357ffa4902952507a500558c366b2d964"
            },
            "downloads": -1,
            "filename": "python_proto_importer-0.1.3-cp38-abi3-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "9a801a6f08383dcfb2b73eeb10ab0924",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.11",
            "size": 1938828,
            "upload_time": "2025-08-11T03:00:39",
            "upload_time_iso_8601": "2025-08-11T03:00:39.377306Z",
            "url": "https://files.pythonhosted.org/packages/72/e8/2cbd2e09f62fc274b31079db7a0715adad7801366c41b952313b2b37d68c/python_proto_importer-0.1.3-cp38-abi3-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "207e9a7d3e0aec3136ba8b0c34be6dd3a908d16756ea6b3dd4934828aca8513b",
                "md5": "f1456b5a541cbad1a09455aa90d46889",
                "sha256": "1b49fe2a071a4955058c0a7f0d9b55b630523ae3109236772f8e888248eb6ff1"
            },
            "downloads": -1,
            "filename": "python_proto_importer-0.1.3.tar.gz",
            "has_sig": false,
            "md5_digest": "f1456b5a541cbad1a09455aa90d46889",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 54627,
            "upload_time": "2025-08-11T03:00:13",
            "upload_time_iso_8601": "2025-08-11T03:00:13.019376Z",
            "url": "https://files.pythonhosted.org/packages/20/7e/9a7d3e0aec3136ba8b0c34be6dd3a908d16756ea6b3dd4934828aca8513b/python_proto_importer-0.1.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-11 03:00:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "K-dash",
    "github_project": "python-proto-importer",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "python-proto-importer"
}
        
Elapsed time: 0.78873s