Release v0.8.0: Agent Property Setters and API Improvements
What's New
✨ Pythonic property assignment for Agent.pos and Agent.velocity
agent.pos = [...]andagent.velocity = [...]now work via PyO3 setters- Boundary projection, history sync, and head-direction normalization are preserved
- Subtle consistency bug fixed: rotational velocity baseline is now kept in lock-step
🗺️ Top-level re-exports
from canns_lib import Agent, Environmentno longer requires thespatialsubmodule
🔧 Deprecations of the legacy set_* methods
Agent.set_position→agent.pos = ...Agent.set_velocity→agent.velocity = ...Agent.set_forced_next_position→agent.update(forced_next_position=...)
Major Features / Key Changes
✨ Property Setters for Agent State (PR #3)
agent.pos = [...]: PyO3 setter delegates to the existingset_positionlogic, so boundary projection and history patching still apply.agent.velocity = [...]: PyO3 setter delegates to the existingset_velocitylogic, including head-direction normalization and history patching.positionalias stays read-only on purpose: allowing external writes would let callers bypass the projection inset_position.- Rotational baseline fix:
set_velocitynow also updatesprev_measured_velocity, so the firstupdate()after a velocity assignment does not record a bogus angular sample.
from canns_lib import Agent, Environment
env = Environment()
a = Agent(env, rng_seed=0)
a.update(dt=0.05)
a.pos = [0.3, 0.7] # was: a.set_position([0.3, 0.7])
a.velocity = [0.0, 0.1] # was: a.set_velocity([0.0, 0.1])🗺️ Top-Level Re-exports (PR #3)
canns_lib.Agentandcanns_lib.Environmentare now the canonical way to import; thespatialsubmodule is still importable for backward compatibility.canns_lib.__version__now comes fromimportlib.metadata(thepython/canns_lib/_version.pyshadow has been removed).
🔧 Deprecations (PR #3)
Agent.set_position/Agent.set_velocity/Agent.set_forced_next_positionall emit aDeprecationWarningand remain functional for one release cycle. The Rust pymethods are kept for source compatibility.- The Python
@propertysetters on the wrapper class route through the real Rustset_position/set_velocity, so property assignment does not silently shadow the Rust getter via__getattr__.
🔧 Build & Test Fixes (PR #2, PR #3)
cargo test --releaseworks out of the box on macOS/Linux. The PyO3extension-modulefeature is now an optional Cargo feature; maturin enables it via[tool.maturin] features(PyO3 FAQ Option 1).- Fixed a
ZeroDivisionErrorintests/test_complex_topology.py(#2).
🚀 Performance Polish (PR #3)
apply_set_velocitynow usesVec::clone_fromto avoid two redundant heap allocations on every call.
🧹 Cleanup (PR #3)
- Removed 2,717-line dead file
src/ripser/ripser_old.rs. - Removed 8 unused Cargo dependencies (
sprs,indexmap,typed-arena,num-traits,thiserror, dev-approx, dev-criterion, dev-rand). - Removed
python/canns_lib/_version.py;canns_lib.__version__is read from installed package metadata. - Trimmed
_ripser_core/_spatial_corefrom__all__(still importable). - Fixed broken imports in
example/try.py(it pointed at a non-existentcanns_ripserpackage and unconditionally required the upstreamripser).
📖 Documentation (PR #3)
- Shipped
docs/SPATIAL_NAV_MODULE_DESIGN.md(no longer gitignored). - Updated module layout in the design doc to match the actual
agent.rs/environment.rs/geometry.rs/state.rs/utils.rsfiles. CLAUDE.mddocuments the newcargo testbehavior and theextension-modulefeature flag.
Breaking Changes
None. All deprecations are soft — existing code continues to work, but the legacy set_* methods emit a DeprecationWarning. The PyO3 extension-module feature is now opt-in, which only affects callers who build the crate as a Rust library (none expected — it ships as a cdylib).
Technical Notes
- Property setters in Rust use the PyO3
#[setter]macro, which requires the method name to follow theset_<field>pattern (set_pos,set_velocity). The originalpub fn set_velocityis preserved asset_velocity_methodwith#[pyo3(name = "set_velocity")]so the Python API is unchanged. - The
extension-moduleCargo feature is added to the[features]table and gated by maturin; the PyO3 FAQ documents this as the recommended workaround for the__Py_TrueStructlinker error on macOS/Linux.
Full Changelog: v0.7.0...v0.8.0