Restructure coglet Python module to improve separation of structure and prepare for publishing#2710
Merged
tempusfrangit merged 13 commits intomainfrom Feb 10, 2026
Merged
Restructure coglet Python module to improve separation of structure and prepare for publishing#2710tempusfrangit merged 13 commits intomainfrom
tempusfrangit merged 13 commits intomainfrom
Conversation
Add build script that: - Converts semver pre-release tags to PEP 440 format (e.g., 0.17.0-alpha.2 → 0.17.0a2) - Captures git SHA, build timestamp, and rustc version - Emits as compile-time environment variables Add frozen BuildInfo pyclass for coglet.__build__ with version, git_sha, build_time, and rustc_version fields.
…ignal handler Replace module setattr + Python string exec with: - OnceLock<Py<PyAny>> static for the exception class - Rust #[pyfunction] signal handler Eliminates a setattr on the coglet module (needed for upcoming module write protection) and removes Python-as-string.
…g target audit.rs: - Replace 60-line Python string with Rust #[pyfunction] audit hook - Add AtomicBool re-entrancy guard (replaces threading.Timer hack) - Add Mutex to serialize stream replacement across threads - Demote helper functions from #[pyfunction] to pub(crate) - Rename TeeWriter -> _TeeWriter (private pyclass) worker_tracing_layer.rs: - Add coglet::worker_local target filter (excluded from IPC, always written to worker stderr fd 101) - Used by audit.rs for poisoned-lock diagnostics that must not traverse the log routing infrastructure
Make the log writer class private in the Python namespace via pyclass(name = "_SlotLogWriter"). Rust type name unchanged.
…edictor Move _collect_async_gen and _ctx_wrapper Python async helper functions into OnceLock statics so they are defined once and reused across calls. Fix Py<PyAny>::call1() call sites to pass py token as first argument.
…tr__ - Remove standalone active() #[pyfunction], expose via __getattr__ as property-like attribute (no parens needed) - Add __getattr__ for 'active' and '__build__' attribute access - Add __dir__ returning only public API: __version__, __build__, active, serve - Add __setattr__ to block writes to module (registered LAST in init) - Use PEP 440 version from COGLET_PEP440_VERSION env var - Store BuildInfo as _build_info, exposed as __build__ via __getattr__
- coglet.server: frozen Server pyclass with .active property, .serve(), ._run_worker(), ._is_cancelable() - coglet._sdk: submodule for Python runtime integration classes (_SlotLogWriter, _TeeWriter) - Root module is plain: __version__, __build__, server, _sdk - No PEP 562 machinery needed — static attrs in dict, dynamic .active is a #[getter] on frozen pyclass - Update all callsites: http.py, orchestrator.rs, tests, docs
…__.py - coglet/__init__.py: explicit re-exports with __all__ control - coglet/py.typed: marker for type stub distribution - pyproject.toml: module-name = coglet._impl for mixed layout - lib.rs: #[pyo3(name = "_impl")] + __all__ for import control - .gitignore: add *.so, *.pyd to prevent committing build artifacts - Maturin now builds as mixed python/rust project, no auto-generated wrapper
- Remove stale root coglet.pyi, replace with coglet/__init__.pyi (mypy stubgen) and coglet/_sdk/__init__.pyi (pyo3-stub-gen) - pyproject.toml: add python-source = '.' for pyo3-stub-gen mixed layout - mise.toml: update generate:stubs to run pyo3-stub-gen then mypy stubgen - mise.toml: rewrite stub:check to use git diff on all .pyi files - mise.toml: update stub:typecheck path
Tests for: PEP 440 version, BuildInfo fields/frozen/repr, server.active property, server frozen protection, _sdk submodule contents, __all__ excludes internals. 17 new tests, all passing.
Contributor
Author
|
Go lint is toast please review as go lint is fixed in #2711 and we'll rebase once that lands. Ignore the transient gotestyourself mise error as well. I'm sure it'll resolve or we'll figure out another path independent of this PR. |
tempusfrangit
commented
Feb 10, 2026
Comment on lines
+452
to
+460
| /// Module `__setattr__` — blocks writes to the module to prevent accidental mutation. | ||
| /// | ||
| /// Registered LAST in module init so it doesn't prevent our own setup. | ||
| #[pyfunction] | ||
| fn __setattr__(name: &str, _value: &Bound<'_, PyAny>) -> PyResult<()> { | ||
| Err(pyo3::exceptions::PyAttributeError::new_err(format!( | ||
| "cannot set '{name}' on module 'coglet'" | ||
| ))) | ||
| } |
Contributor
Author
There was a problem hiding this comment.
the pep for this was rejected, restructured in a later commit out.
michaeldwan
approved these changes
Feb 10, 2026
Member
michaeldwan
left a comment
There was a problem hiding this comment.
@tempusfrangit walked us through live. looks sensible.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR restructures the coglet Python module to provide a clean public API. Replaces the flat function-based module with frozen pyclasses and submodules, fixes PEP 440 version compliance, rewrites Python string exec blocks in Rust, and sets up a proper mixed-layout build with two-stage stub generation.
Module layout (before -> after)
Before:
coglet.serve(...)-- top-level functioncoglet.active()-- required parenthesescoglet._run_worker()/coglet._is_cancelable()-- top-levelcoglet.SlotLogWriter/coglet.TeeWriter-- publicly visible internalscoglet.coglet-- maturin double-export artifact indir()After:
coglet.__version__-- PEP 440 compliantcoglet.__build__-- frozen BuildInfo with git sha, build time, rustc versioncoglet.server.serve(...)-- method on frozen Server pyclasscoglet.server.active-- bool property, no parenscoglet.server._run_worker()/coglet.server._is_cancelable()-- internal methodscoglet._sdk._SlotLogWriter/coglet._sdk._TeeWriter-- submodule for runtime integrationKey changes
coglet/__init__.pywithmodule-name = "coglet._impl"to avoid maturin's auto-generated wrapperTesting
17 new unit tests for module structure (version format, BuildInfo, frozen protection, server.active, _sdk contents, all). All existing integration tests updated and passing.