Skip to content

Commit

Permalink
Merge pull request #263 from personalrobotics/bugfix/infinite_recursion
Browse files Browse the repository at this point in the history
Refactored robot __getattr__ to resist infinite recursion. Resolves #262
  • Loading branch information
ClintLiddick committed Jan 27, 2016
2 parents 5aa9150 + 1dc571f commit 0496943
Showing 1 changed file with 33 additions and 21 deletions.
54 changes: 33 additions & 21 deletions src/prpy/base/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,41 +97,53 @@ def __dir__(self):
def __getattr__(self, name):
# We have to manually perform a lookup in InstanceDeduplicator because
# __methods__ bypass __getattribute__.
self = bind.InstanceDeduplicator.get_canonical(self)
canonical = bind.InstanceDeduplicator.get_canonical(self)

# For special properties, we do NOT want to recursively look them up.
# If they are not found on the canonical instance, stop looking.
if canonical == self:
if name in ['planner', 'actions', 'detector']:
raise AttributeError('{0:s} is missing method "{1:s}".'
.format(repr(canonical), name))

if (name != 'planner'
and hasattr(self, 'planner')
and self.planner is not None
and self.planner.has_planning_method(name)):
# For other methods, search the special properties for meta-methods.
if (name != 'planner' and
hasattr(canonical, 'planner') and
canonical.planner is not None and
canonical.planner.has_planning_method(name)):

delegate_method = getattr(canonical.planner, name)

delegate_method = getattr(self.planner, name)
@functools.wraps(delegate_method)
def wrapper_method(*args, **kw_args):
return self._PlanWrapper(delegate_method, args, kw_args)
return canonical._PlanWrapper(delegate_method, args, kw_args)

return wrapper_method
elif (name != 'actions'
and hasattr(self, 'actions')
and self.actions is not None
and self.actions.has_action(name)):
elif (name != 'actions' and
hasattr(canonical, 'actions') and
canonical.actions is not None and
canonical.actions.has_action(name)):

delegate_method = canonical.actions.get_action(name)

delegate_method = self.actions.get_action(name)
@functools.wraps(delegate_method)
def wrapper_method(*args, **kw_args):
return delegate_method(self, *args, **kw_args)
return delegate_method(canonical, *args, **kw_args)
return wrapper_method
elif (name != 'detector'
and hasattr(self, 'detector')
and self.detector is not None
and self.detector.has_perception_method(name)):

delegate_method = getattr(self.detector, name)
elif (name != 'detector' and
hasattr(canonical, 'detector') and
canonical.detector is not None and
canonical.detector.has_perception_method(name)):

delegate_method = getattr(canonical.detector, name)

@functools.wraps(delegate_method)
def wrapper_method(*args, **kw_args):
return delegate_method(self, *args, **kw_args)
return delegate_method(canonical, *args, **kw_args)
return wrapper_method

raise AttributeError('{0:s} is missing method "{1:s}".'.format(repr(self), name))
raise AttributeError('{0:s} is missing method "{1:s}".'
.format(repr(canonical), name))

def CloneBindings(self, parent):
self.planner = parent.planner
Expand Down

0 comments on commit 0496943

Please sign in to comment.