From f60d04f762a082ac7d40fb39cc781601d168411c Mon Sep 17 00:00:00 2001 From: John McCardle Date: Sat, 25 Oct 2025 20:58:22 +0000 Subject: [PATCH] Add "Python-Binding-Layer" --- Python-Binding-Layer.-.md | 187 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 Python-Binding-Layer.-.md diff --git a/Python-Binding-Layer.-.md b/Python-Binding-Layer.-.md new file mode 100644 index 0000000..6566f7b --- /dev/null +++ b/Python-Binding-Layer.-.md @@ -0,0 +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 +- See [#126](../../issues/126) for automated generation progress \ No newline at end of file