Metadata-Version: 2.1
Name: wexample-pseudocode
Version: 9.4.5
Summary: Converts Python source to a YAML pseudocode schema of its classes, functions, and constants, and regenerates Python code from that schema
Author-Email: weeger <contact@wexample.com>
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Project-URL: homepage, https://github.com/wexample/python-pseudocode
Requires-Python: >=3.10
Requires-Dist: attrs>=23.1.0
Requires-Dist: cattrs>=23.1.0
Requires-Dist: wexample-helpers>=19.1.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Description-Content-Type: text/markdown

# pseudocode

Version: 9.4.5

`wexample-pseudocode` parses Python source files into a YAML schema that describes their classes, functions, and constants, then regenerates Python code from that same schema. It targets Python developers who need a language-neutral intermediate representation of a module's public surface — for documentation, cross-language code generation, or schema-driven scaffolding.

## Table of Contents

- [Installation](#installation)
- [Quickstart](#quickstart)
- [Tests](#tests)
- [Architecture](#architecture)
- [Integration in the Suite](#integration-in-the-suite)
- [Dependencies](#dependencies)
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
- [License](#license)
- [About us](#about-us)
- [Known Limitations & Roadmap](#known-limitations--roadmap)
- [Status & Compatibility](#status--compatibility)
- [Useful Links](#useful-links)
- [Migration Notes](#migration-notes)

## Installation

```bash
pip install wexample-pseudocode
```

Requires Python >=3.10.

## Quickstart

```bash
pip install wexample-pseudocode
```

Parse Python source into a YAML pseudocode schema:

```python
from wexample_pseudocode.generator.pseudocode_generator import PseudocodeGenerator

source = "MAX_RETRIES = 3  # Maximum number of retries for API calls\n"

gen = PseudocodeGenerator()
data = gen.generate_config_data(source)
print(gen.dump_pseudocode(data))
```

Output:

```yaml
items:
- type: constant
  name: MAX_RETRIES
  value: 3
  description: Maximum number of retries for API calls
```

To go the other direction and regenerate Python from that YAML, use `CodeGenerator`:

```python
from wexample_pseudocode.generator.code_generator import CodeGenerator

yaml_input = """\
items:
  - type: constant
    name: MAX_RETRIES
    value: 3
    description: Maximum number of retries for API calls
"""

gen = CodeGenerator()
print(gen.generate(yaml_input))
# MAX_RETRIES = 3  # Maximum number of retries for API calls
```

## Tests

This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.

### Installation

First, install the required testing dependencies:
```bash
.venv/bin/python -m pip install pytest pytest-cov
```

### Basic Usage

Run all tests with coverage:
```bash
.venv/bin/python -m pytest --cov --cov-report=html
```

### Common Commands
```bash
# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
```

### Viewing HTML Reports

After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.

### Coverage Threshold

To enforce a minimum coverage percentage:
```bash
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
```

This will cause the test suite to fail if coverage drops below 80%.

## Architecture

The package has four directories under `src/wexample_pseudocode/`, each owning a distinct responsibility. A call always enters through `generator/`, borrows from `common/`, then either walks through `parser/` (Python → YAML) or through `config/` (YAML → Python).

### `generator/` — the public entry points

src/wexample_pseudocode/generator/abstract_generator.py defines `AbstractGenerator`. It provides one concrete static method — `dump_pseudocode(data: dict) -> str`, a thin wrapper around `yaml.safe_dump` bound with `sort_keys=False` — and one abstract contract: `generate_config_data(source_code: str) -> dict`.

Two subclasses implement the two directions of the pipeline:

- src/wexample_pseudocode/generator/pseudocode_generator.py — **Python → YAML**. `PseudocodeGenerator.generate_config_data()` calls all three parsers in order, applies `normalize_type()` to every annotation it touches, and returns `{"items": [...]}`. Passing that dict to `dump_pseudocode()` produces the YAML string.

- src/wexample_pseudocode/generator/code_generator.py — **YAML → Python**. `CodeGenerator.generate()` calls `yaml.safe_load()`, optionally builds a `GeneratorConfig` from a top-level `"generator"` key, then dispatches each item dict to a config class through a `Registry[type]` keyed by `"constant"`, `"class"`, and `"function"`. It calls `to_code()` on each config object and joins the results.

### `parser/` — AST extraction

All three parsers accept a `source_code: str`, call `ast.parse()` once, and yield typed dataclass items.

- src/wexample_pseudocode/parser/module_parser.py — `parse_module_constants()` yields a `ConstantItem` for every top-level ALL_CAPS name. The inline `#` comment on the assignment line becomes `description`; the value is obtained via `ast.literal_eval` with an `ast.unparse` fallback.

- src/wexample_pseudocode/parser/class_parser.py — `parse_module_classes()` yields a `ClassItem` populated with `ClassProperty` and `ClassMethod` records. Dunder methods are skipped. Docstrings are forwarded to `parse_docstring()`; annotations are serialised with `_annotation_to_str()` (`ast.unparse` with an `ast.Name` fallback), which the function parser re-imports from this module.

- src/wexample_pseudocode/parser/function_parser.py — `parse_module_functions()` yields a `FunctionItem` for each top-level `ast.FunctionDef`. Default argument alignment is derived from `len(args) - len(defaults)`.

### `common/` — shared utilities

- src/wexample_pseudocode/common/docstring.py — `parse_docstring(doc)` returns `{"params": {name: desc, …}, "return": {"description": …}}`. It handles reST/Sphinx (`:param name:`, `:return:`) and Google/NumPy (`Args:`, `Returns:`) blocks in a single pass over the lines.

- src/wexample_pseudocode/common/type_normalizer.py — `normalize_type()` maps Python type strings to schema-neutral names: `list` → `"array"`, `Optional[X]` → the inner type, `typing.` prefix stripped. `to_python_type()` is the inverse, used by config `to_code()` methods when regenerating Python source.

### `config/` — schema items and code rendering

Each config dataclass represents one item kind from the YAML schema. `from_config(data, global_config)` constructs an instance from a parsed YAML dict; `to_code()` renders the item as a Python source fragment.

- src/wexample_pseudocode/config/constant_config.py — `ConstantConfig.to_code()` emits `NAME = value  # description`.

- src/wexample_pseudocode/config/class_config.py — `ClassConfig.to_code()` assembles the class body from `ClassPropertyConfig` and `ClassMethodConfig` fragments.

- src/wexample_pseudocode/config/function_config.py — `FunctionConfig.to_code()` builds the function signature, docstring, and `pass` body from `FunctionParameterConfig` entries.

- src/wexample_pseudocode/config/generator_config.py — `GeneratorConfig` is a slots dataclass with no fields; it mirrors the PHP API and is threaded through `from_config()` calls as a placeholder for future global options.

Sub-item configs — src/wexample_pseudocode/config/class_method_config.py, src/wexample_pseudocode/config/class_property_config.py, src/wexample_pseudocode/config/function_parameter_config.py, src/wexample_pseudocode/config/method_parameter_config.py — each carry the per-item data and expose a `to_code()` that emits a single Python expression (a property annotation, method signature, or parameter fragment).

### Call paths

**Python → YAML**

```
source_code: str
  └─► PseudocodeGenerator.generate_config_data()
        ├─► parse_module_constants()  →  ConstantItem[]
        ├─► parse_module_classes()    →  ClassItem[]    (calls parse_docstring, _annotation_to_str)
        └─► parse_module_functions()  →  FunctionItem[] (calls parse_docstring, _annotation_to_str)
              │
              │  normalize_type() applied to every type annotation
              ▼
        dict {"items": [...]}
              │
              ▼  AbstractGenerator.dump_pseudocode()
        YAML string
```

**YAML → Python**

```
yaml_input: str
  └─► CodeGenerator.generate()
        └─► _generate_config()
              ├─► yaml.safe_load()
              ├─► GeneratorConfig.from_config()   (if "generator" key present)
              └─► Registry dispatch on item["type"]
                    └─► ConstantConfig | ClassConfig | FunctionConfig .from_config()
                          │
                          ▼  .to_code()
        Python source (joined with "\n")
```

## Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

### Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.

## Dependencies

- attrs: >=23.1.0
- cattrs: >=23.1.0
- wexample-helpers: >=19.1.0

## Versioning & Compatibility Policy

Wexample packages follow **Semantic Versioning** (SemVer):

- **MAJOR**: Breaking changes
- **MINOR**: New features, backward compatible
- **PATCH**: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

Free to use in both personal and commercial projects.

## About us

[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

## Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the [project roadmap](https://github.com/wexample/python-pseudocode/issues) for upcoming features and improvements.

## Status & Compatibility

**Maturity**: Production-ready

**Python Support**: >=3.10

**OS Support**: Linux, macOS, Windows

**Status**: Actively maintained

## Useful Links

- **Homepage**: https://github.com/wexample/python-pseudocode
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
- **Issue Tracker**: https://github.com/wexample/python-pseudocode/issues
- **Discussions**: https://github.com/wexample/python-pseudocode/discussions
- **PyPI**: [pypi.org/project/wexample-pseudocode](https://pypi.org/project/wexample-pseudocode/)

## Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.
