Conversation
Closes #373. `Controller.path` is now a keyword-only ``__init__`` parameter on ``BaseController`` (default ``[]``) and is threaded through user code rather than seeded post-construction. The launcher builds each root with ``cls(options, path=[entry.id])`` (or ``cls(path=[entry.id])`` when no options); a parent constructs its subs with the full path already baked in (e.g. ``Sub(path=self.path + [name])``). ``BaseController.set_path()`` is removed entirely. ``add_sub_controller(name, sub)`` no longer mutates ``sub._path`` -- it sanity-asserts ``sub.path == parent.path + [name]`` and rejects the call with a clear error if the caller forgot to thread the path. ``_build_api()`` reads ``self._path`` directly, eliminating the parent-side path argument and the recursive re-prefix it required. Custom ``Controller.__init__`` (root and sub-controller alike) must now accept ``path`` and forward it to ``super().__init__``. Demo controllers and doc snippets are updated to the new shape; tests either construct with ``path=[...]`` from the start or move the id declaration above the controller construction so sub paths can be threaded explicitly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughControllers now accept a ChangesConstructor-based path initialization
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #382 +/- ##
==========================================
- Coverage 91.20% 91.18% -0.02%
==========================================
Files 72 72
Lines 2875 2870 -5
==========================================
- Hits 2622 2617 -5
Misses 253 253 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
docs/snippets/static10.py (1)
76-76: 💤 Low valueConsider using unpacking syntax for list concatenation.
The expression
self.path + [name]can be written more idiomatically as[*self.path, name].♻️ Optional refactor
- controller = TemperatureRampController( - index, self._connection, path=self.path + [name] - ) + controller = TemperatureRampController( + index, self._connection, path=[*self.path, name] + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/snippets/static10.py` at line 76, Replace the list concatenation expression used when passing the path parameter to the constructor/call (currently written as self.path + [name]) with Python unpacking to produce the same list more idiomatically (use [*self.path, name]); update the call that constructs/passes path (the invocation that includes index, self._connection, path=...) so it uses [*self.path, name] instead of self.path + [name] to keep behaviour identical while improving readability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@docs/snippets/static10.py`:
- Line 76: Replace the list concatenation expression used when passing the path
parameter to the constructor/call (currently written as self.path + [name]) with
Python unpacking to produce the same list more idiomatically (use [*self.path,
name]); update the call that constructs/passes path (the invocation that
includes index, self._connection, path=...) so it uses [*self.path, name]
instead of self.path + [name] to keep behaviour identical while improving
readability.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c9ca75e8-d358-4607-b28c-109bce0905e5
📒 Files selected for processing (33)
docs/snippets/dynamic.pydocs/snippets/static04.pydocs/snippets/static05.pydocs/snippets/static06.pydocs/snippets/static07.pydocs/snippets/static08.pydocs/snippets/static09.pydocs/snippets/static10.pydocs/snippets/static11.pydocs/snippets/static12.pydocs/snippets/static13.pydocs/snippets/static14.pydocs/snippets/static15.pysrc/fastcs/controllers/base_controller.pysrc/fastcs/controllers/controller.pysrc/fastcs/controllers/controller_vector.pysrc/fastcs/demo/controllers.pysrc/fastcs/launch.pytests/assertable_controller.pytests/benchmarking/controller.pytests/conftest.pytests/example_p4p_ioc.pytests/example_softioc.pytests/test_controllers.pytests/test_launch.pytests/test_multi_controller.pytests/transports/epics/ca/test_gui.pytests/transports/epics/ca/test_initial_value.pytests/transports/epics/ca/test_softioc.pytests/transports/epics/pva/test_p4p.pytests/transports/epics/test_emission.pytests/transports/graphQL/test_graphql.pytests/transports/tango/test_dsr.py
Summary
Implements branch 2d from #373:
pathbecomes a keyword-only constructor parameter onBaseController/Controller/ControllerVector; the launcher passespath=[entry.id]rather than callingset_pathafter construction.BaseController.set_path()is removed.add_sub_controller(name, sub)now sanity-assertssub.path == parent.path + [name]instead of mutatingsub._path. Parents construct subs with the full path baked in (e.g.Sub(path=self.path + [name]))._build_api()readsself._pathdirectly; the parent-sidepathargument and recursive re-prefix are gone.controller.set_path([id])are updated to threadpath=[...]through__init__.Closes #373.
Notes on the open sub-decisions
pathis keyword-only — keeps existing positional call-sites (description, ios, settings, …) intact.pathdefaults to[]so direct/standalone construction (tests, embedded use) still works.add_sub_controller's residual role: strict sanity-assert (full path match), not justpath[-1] == name. This catches the common mistake of forgetting to threadpathend-to-end and is what every updated test relies on for diagnostics.Test plan
pytest tests/test_controllers.py tests/test_multi_controller.py tests/test_launch.py tests/test_attributes.py tests/test_methods.py tests/test_attribute_logging.py tests/test_control_system.py tests/test_util.py tests/test_ip_connection.py tests/transports/rest tests/transports/graphQL tests/transports/epics/test_emission.py tests/transports/epics/ca/test_gui.py tests/transports/epics/ca/test_softioc.py tests/transports/epics/ca/test_ca_util.py— all pass locally (one pre-existing flaky thread-cleanup failure intest_scan_exception_sets_disconnected_and_reconnect_resumes, order-dependent, passes when run alone).static04..15anddynamic.pyimport and execute cleanly.🤖 Generated with Claude Code
Summary by CodeRabbit
Refactor
pathparameter instead of callingset_path()after instantiation. Theset_path()method has been removed.Documentation