-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: rework tree serialization, accompanying tests #30
Conversation
def get_all_subclasses(cls: type) -> Iterator[type]: | ||
"""Recursive implementation of type.__subclasses__""" | ||
for sub_cls in cls.__subclasses__(): | ||
yield sub_cls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beginning to get comfortable with this pythonic yield idea used in recursion, still might need my own toy example to understand it well enough to explain simply
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: it seems this should actually be hinted as returning a Generator oops
In this case the yield is just pausing calculation and "yielding" the value. Iterators Generators are a way to do make sure we only do calculations when we want the next value.
Using a generator is the same as using a fully defined list or other iterator, we just doesn't know a-priori how long that generator is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type hinting documentation presents Iterator[type]
and Iterable[type]
as fully-allowable sub-ins for Generator[type, None, None]
(I think because they behave the same way to the end user)
"Pv": "PERC:COMP", | ||
"Mode": "INC", | ||
"Value": 10 | ||
"root": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wish i could heart react files this looks great!
beams/tree_config.py
Outdated
@as_tagged_union | ||
@dataclass | ||
class ActionItem(BaseItem): | ||
loop_freq: float = 1.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
crazy pedantic, I may have even suggested the original name.
loop_freq: float = 1.0 | |
loop_sleep_sec: float = 1.0 |
Not a huge fan of this either (does not roll off tongue) but makes it very clear to others what it is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critically this is the period, not the frequency 🤦
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True too, but as other things may also take up clock cycles in the action I think indicating it as a sleep could be helpful. Semantics, whatever you pick is good.
def get_condition_function(self) -> Callable[[], bool]: | ||
op = getattr(operator, self.operator.value) | ||
|
||
def cond_func(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder to myself / us in a future PR to potentially nest this in a subclass much the same as we have done with ActionItem
that hardcodes this type of Conditional (where we are only cagetting) such that we can have a slightly more generic ConditionNode baseclass
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this should definitely be a PVComparisonConditionItem
or something
Linking issue #32, will build off of this awesome work |
|
||
|
||
@dataclass | ||
class BehaviorTreeItem: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if more things should subclass this and not base item so that they have the root object to tick? tell me if I am misunderstanding design
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding of py_trees is that all "trees" should be a py_trees.tree.BehaviourTree
. The root node of that BehaviourTree
gives the pre/post tick hooks and other logging niceties. https://py-trees.readthedocs.io/en/devel/trees.html
We can individually tick nodes / sub-trees (and we should during testing), but when ingesting a full behavior tree I think this is probably the object we should interact with
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super potent PR, awesome stuff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on board, just one seemingly unused and undocumented thing that confused me
|
||
|
||
def alternative_constructor(func: Func) -> Func: | ||
"""Alternative constructor for a given type.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this function used for? It looks like it essentially registers another function (not stated in the docstrings here), but I don't see any place where this is called in beams. I do see one place where the empty constructors stash is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use it, but we could if we wanted to create an alternative constructor. We don't make use of this but it came as part of the magic spell from wyfo:
@alternative_constructor
def sized_line(
start: float, stop: float, size: Annotated[float, schema(min=1)]
) -> "Line":
return Line(start=start, stop=stop, step=(stop - start) / (size - 1))
https://wyfo.github.io/apischema/0.18/examples/subclass_tagged_union/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it's used for some un-tagged union parsing, but that's a deeper dive I'd need some time to complete wyfo/apischema#56 (reply in thread)
Description
BaseItem
subclassBaseItem
has aget_tree
method that returns the py_trees.behaviour.Behaviour` specified by the dataclassMotivation and Context
Closes #18
How Has This Been Tested?
Tests have been adjusted
Where Has This Been Documented?
This PR
Pre-merge checklist
docs/pre-release-notes.sh
and created a pre-release documentation page