diff --git a/Python-Binding-Layer.-.md b/Python-Binding-Layer.md similarity index 96% rename from Python-Binding-Layer.-.md rename to Python-Binding-Layer.md index 6566f7b..9a87f9b 100644 --- a/Python-Binding-Layer.-.md +++ b/Python-Binding-Layer.md @@ -1,187 +1,187 @@ -# Python Binding Layer - -The Python Binding Layer exposes C++ engine functionality to Python using Python's C API. This system allows game logic to be written in Python while maintaining C++ rendering performance. - -## Quick Reference - -**Related Issues:** -- [#126](../../issues/126) - Generate Perfectly Consistent Python Interface (Tier 1) -- [#109](../../issues/109) - Vector Convenience Methods -- [#101](../../issues/101) - Standardize Constructor Arguments -- [#92](../../issues/92) - Inline C++ Documentation System -- [#91](../../issues/91) - Generate Python Type Stub Files (.pyi) - -**Key Files:** -- `src/McRFPy_API.h` / `src/McRFPy_API.cpp` - Main Python module definition -- `src/PyObjectUtils.h` - Utility functions for Python/C++ conversion -- `src/UIDrawable.h` - `RET_PY_INSTANCE` macro pattern -- Individual class binding files: `src/UI*.cpp` (PyGetSetDef arrays) - -**Reference Documentation:** -- `PYTHON_BINDING_PATTERNS.md` - Comprehensive pattern reference (repo root) -- [[Adding-Python-Bindings]] - Step-by-step workflow guide - -## Architecture Overview - -### Module Structure - -``` -mcrfpy (C extension module) -├── Types (Frame, Caption, Sprite, Grid, Entity, etc) -├── Functions (createScene, setScene, animate, etc) -├── Constants (SFML key codes, etc) -└── Submodules - └── libtcod (TCOD bindings) -``` - -**Entry Point:** `src/McRFPy_API.cpp::PyInit_mcrfpy()` - -### Binding Patterns - -#### Pattern 1: PyGetSetDef for Properties - -Properties exposed via getter/setter arrays: - -```cpp -PyGetSetDef PyUISprite::getsetters[] = { - {"x", (getter)Drawable::get_member, (setter)Drawable::set_member, - "X coordinate", (void*)SPRITE_X}, - {"texture", (getter)PyUISprite::get_texture, (setter)PyUISprite::set_texture, - "Sprite texture", NULL}, - {NULL} // Sentinel -}; -``` - -**Closure Parameter:** Used to identify which property is being accessed -- Simple types: Integer values (0, 1, 2, 3) -- UIDrawable types: `(void*)((intptr_t)PyObjectsEnum::TYPE << 8 | member_index)` - -**See:** `PYTHON_BINDING_PATTERNS.md` for complete closure encoding reference - -#### Pattern 2: PyMethodDef for Methods - -Methods exposed via method definition arrays: - -```cpp -PyMethodDef PyUIGrid::methods[] = { - {"at", (PyCFunction)PyUIGrid::at, METH_VARARGS | METH_KEYWORDS, - "at(pos: tuple) -> GridPoint\n\n" - "Access grid cell at position.\n\n" - "Args:\n" - " pos: (x, y) tuple\n\n" - "Returns:\n" - " GridPoint object at that position"}, - {NULL} -}; -``` - -**Inline Documentation:** Docstrings extracted by `tools/generate_dynamic_docs.py` - -#### Pattern 3: RET_PY_INSTANCE Macro - -Converting C++ objects to Python requires type-aware allocation: - -```cpp -RET_PY_INSTANCE(target); -// Expands to switch on target->derived_type(): -// - Allocates correct Python type (Frame, Caption, Sprite, Grid) -// - Assigns shared_ptr to data member -// - Returns PyObject* -``` - -**File:** `src/UIDrawable.h::RET_PY_INSTANCE` macro definition - -## Common Patterns - -### Adding a Property - -See [[Adding-Python-Bindings]] for complete step-by-step workflow. - -**Quick reference:** -1. Add to PyGetSetDef array -2. Implement getter/setter functions -3. Encode closure parameter -4. Add inline documentation -5. Test with Python - -### Type Preservation in Collections - -**Challenge:** Shared pointers can lose Python type information - -**Solution:** -- Use `RET_PY_INSTANCE` when returning from collections -- Maintain Python object references when needed -- See [#112](../../issues/112) for object splitting bug details - -### Constructor Standardization - -**Current state:** Inconsistent constructor patterns across types - -**Planned:** [#101](../../issues/101) - Standardize all constructors to accept: -- Position as `(x, y)` tuple or separate `x, y` args -- Size as `(w, h)` tuple or separate `w, h` args -- Consistent default values (usually `(0, 0)`) - -## Key Subsystems - -### PyArgHelpers - -Standardized argument parsing for tuples vs separate args: - -```cpp -// Accept both (x, y) and x, y formats -PyArgParseTuple_IntIntHelper(args, kwds, x, y, "position", "x", "y"); -``` - -**Files:** -- `src/PyArgHelpers.h` - Helper function definitions -- Used throughout `src/UI*.cpp` for constructor consistency - -### Documentation Extraction - -**Pipeline:** -1. C++ docstrings in PyMethodDef/PyGetSetDef arrays -2. Compilation embeds docstrings in module -3. `tools/generate_dynamic_docs.py` extracts via introspection -4. Generates `docs/api_reference_dynamic.html` - -**Format:** See CLAUDE.md "Inline C++ Documentation Format" section - -## Current Issues & Limitations - -**Consistency Issues:** -- [#126](../../issues/126): Need automated generation for perfect consistency -- [#101](../../issues/101): Constructor arguments vary by type -- [#109](../../issues/109): Vector lacks `[0]`, `[1]` indexing - -**Type Preservation:** -- Collections can lose Python derived types -- Workaround: `RET_PY_INSTANCE` macro -- Long-term: Better type tracking in C++ - -## Related Systems - -- [[UI-Component-Hierarchy]] - Classes exposed to Python -- [[Grid-System]] - Grid/Entity Python API -- [[Animation-System]] - `animate()` function binding - -## Design Decisions - -**Why Python C API vs pybind11/SWIG?** -- Fine-grained control over type system -- Direct integration with CPython internals -- No third-party dependencies -- Performance: Zero-overhead abstraction - -**Tradeoffs:** -- More verbose than pybind11 -- Manual memory management required -- Type checking done manually -- But: Full control, no "magic" - ---- - -**Next Steps:** -- Review [[Adding-Python-Bindings]] workflow -- Study `PYTHON_BINDING_PATTERNS.md` for complete patterns +# Python Binding Layer + +The Python Binding Layer exposes C++ engine functionality to Python using Python's C API. This system allows game logic to be written in Python while maintaining C++ rendering performance. + +## Quick Reference + +**Related Issues:** +- [#126](../../issues/126) - Generate Perfectly Consistent Python Interface (Tier 1) +- [#109](../../issues/109) - Vector Convenience Methods +- [#101](../../issues/101) - Standardize Constructor Arguments +- [#92](../../issues/92) - Inline C++ Documentation System +- [#91](../../issues/91) - Generate Python Type Stub Files (.pyi) + +**Key Files:** +- `src/McRFPy_API.h` / `src/McRFPy_API.cpp` - Main Python module definition +- `src/PyObjectUtils.h` - Utility functions for Python/C++ conversion +- `src/UIDrawable.h` - `RET_PY_INSTANCE` macro pattern +- Individual class binding files: `src/UI*.cpp` (PyGetSetDef arrays) + +**Reference Documentation:** +- `PYTHON_BINDING_PATTERNS.md` - Comprehensive pattern reference (repo root) +- [[Adding-Python-Bindings]] - Step-by-step workflow guide + +## Architecture Overview + +### Module Structure + +``` +mcrfpy (C extension module) +├── Types (Frame, Caption, Sprite, Grid, Entity, etc) +├── Functions (createScene, setScene, animate, etc) +├── Constants (SFML key codes, etc) +└── Submodules + └── libtcod (TCOD bindings) +``` + +**Entry Point:** `src/McRFPy_API.cpp::PyInit_mcrfpy()` + +### Binding Patterns + +#### Pattern 1: PyGetSetDef for Properties + +Properties exposed via getter/setter arrays: + +```cpp +PyGetSetDef PyUISprite::getsetters[] = { + {"x", (getter)Drawable::get_member, (setter)Drawable::set_member, + "X coordinate", (void*)SPRITE_X}, + {"texture", (getter)PyUISprite::get_texture, (setter)PyUISprite::set_texture, + "Sprite texture", NULL}, + {NULL} // Sentinel +}; +``` + +**Closure Parameter:** Used to identify which property is being accessed +- Simple types: Integer values (0, 1, 2, 3) +- UIDrawable types: `(void*)((intptr_t)PyObjectsEnum::TYPE << 8 | member_index)` + +**See:** `PYTHON_BINDING_PATTERNS.md` for complete closure encoding reference + +#### Pattern 2: PyMethodDef for Methods + +Methods exposed via method definition arrays: + +```cpp +PyMethodDef PyUIGrid::methods[] = { + {"at", (PyCFunction)PyUIGrid::at, METH_VARARGS | METH_KEYWORDS, + "at(pos: tuple) -> GridPoint\n\n" + "Access grid cell at position.\n\n" + "Args:\n" + " pos: (x, y) tuple\n\n" + "Returns:\n" + " GridPoint object at that position"}, + {NULL} +}; +``` + +**Inline Documentation:** Docstrings extracted by `tools/generate_dynamic_docs.py` + +#### Pattern 3: RET_PY_INSTANCE Macro + +Converting C++ objects to Python requires type-aware allocation: + +```cpp +RET_PY_INSTANCE(target); +// Expands to switch on target->derived_type(): +// - Allocates correct Python type (Frame, Caption, Sprite, Grid) +// - Assigns shared_ptr to data member +// - Returns PyObject* +``` + +**File:** `src/UIDrawable.h::RET_PY_INSTANCE` macro definition + +## Common Patterns + +### Adding a Property + +See [[Adding-Python-Bindings]] for complete step-by-step workflow. + +**Quick reference:** +1. Add to PyGetSetDef array +2. Implement getter/setter functions +3. Encode closure parameter +4. Add inline documentation +5. Test with Python + +### Type Preservation in Collections + +**Challenge:** Shared pointers can lose Python type information + +**Solution:** +- Use `RET_PY_INSTANCE` when returning from collections +- Maintain Python object references when needed +- See [#112](../../issues/112) for object splitting bug details + +### Constructor Standardization + +**Current state:** Inconsistent constructor patterns across types + +**Planned:** [#101](../../issues/101) - Standardize all constructors to accept: +- Position as `(x, y)` tuple or separate `x, y` args +- Size as `(w, h)` tuple or separate `w, h` args +- Consistent default values (usually `(0, 0)`) + +## Key Subsystems + +### PyArgHelpers + +Standardized argument parsing for tuples vs separate args: + +```cpp +// Accept both (x, y) and x, y formats +PyArgParseTuple_IntIntHelper(args, kwds, x, y, "position", "x", "y"); +``` + +**Files:** +- `src/PyArgHelpers.h` - Helper function definitions +- Used throughout `src/UI*.cpp` for constructor consistency + +### Documentation Extraction + +**Pipeline:** +1. C++ docstrings in PyMethodDef/PyGetSetDef arrays +2. Compilation embeds docstrings in module +3. `tools/generate_dynamic_docs.py` extracts via introspection +4. Generates `docs/api_reference_dynamic.html` + +**Format:** See CLAUDE.md "Inline C++ Documentation Format" section + +## Current Issues & Limitations + +**Consistency Issues:** +- [#126](../../issues/126): Need automated generation for perfect consistency +- [#101](../../issues/101): Constructor arguments vary by type +- [#109](../../issues/109): Vector lacks `[0]`, `[1]` indexing + +**Type Preservation:** +- Collections can lose Python derived types +- Workaround: `RET_PY_INSTANCE` macro +- Long-term: Better type tracking in C++ + +## Related Systems + +- [[UI-Component-Hierarchy]] - Classes exposed to Python +- [[Grid-System]] - Grid/Entity Python API +- [[Animation-System]] - `animate()` function binding + +## Design Decisions + +**Why Python C API vs pybind11/SWIG?** +- Fine-grained control over type system +- Direct integration with CPython internals +- No third-party dependencies +- Performance: Zero-overhead abstraction + +**Tradeoffs:** +- More verbose than pybind11 +- Manual memory management required +- Type checking done manually +- But: Full control, no "magic" + +--- + +**Next Steps:** +- Review [[Adding-Python-Bindings]] workflow +- Study `PYTHON_BINDING_PATTERNS.md` for complete patterns - See [#126](../../issues/126) for automated generation progress \ No newline at end of file