Skip to content
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

Add meaningful "representation" formatter to object classes #432

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions canopen/objectdictionary/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ def __init__(self, name: str, index: int):
self.subindices = {}
self.names = {}

def __repr__(self) -> str:
return f"<{type(self).__qualname__} '{self.name}' at 0x{self.index:04x}>"
sveinse marked this conversation as resolved.
Show resolved Hide resolved

def __getitem__(self, subindex: Union[int, str]) -> "ODVariable":
item = self.names.get(subindex) or self.subindices.get(subindex)
if item is None:
Expand Down Expand Up @@ -235,6 +238,9 @@ def __init__(self, name: str, index: int):
self.subindices = {}
self.names = {}

def __repr__(self) -> str:
return f"<{type(self).__qualname__} '{self.name}' at 0x{self.index:04x}>"
sveinse marked this conversation as resolved.
Show resolved Hide resolved

def __getitem__(self, subindex: Union[int, str]) -> "ODVariable":
var = self.names.get(subindex) or self.subindices.get(subindex)
if var is not None:
Expand Down Expand Up @@ -330,6 +336,15 @@ def __init__(self, name: str, index: int, subindex: int = 0):
#: Can this variable be mapped to a PDO
self.pdo_mappable = False

def __repr__(self) -> str:
suffix = f":{self.subindex:02x}" if isinstance(self.parent, (ODRecord, ODArray)) else ""
return f"<{type(self).__qualname__} '{self.qualname}' at 0x{self.index:04x}{suffix}>"
sveinse marked this conversation as resolved.
Show resolved Hide resolved

@property
def qualname(self) -> str:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a docstring, as it is not obvious what qualname means and how it differs from name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Updated.

-- Having qualname on this object only hurts my eye a little bit, but its due to the special naming regime that pertains to this object only. Adding qualname to all the others will just be a do-nothing object for the purpose of duck typing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with having it only here. It's purely for internal use right now.

if isinstance(self.parent, (ODRecord, ODArray)):
return f"{self.parent.name}.{self.name}"
return self.name

def __eq__(self, other: "ODVariable") -> bool:
return (self.index == other.index and
Expand Down
6 changes: 3 additions & 3 deletions canopen/pdo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging

from canopen import node
from canopen.pdo.base import PdoBase, Maps
from canopen.pdo.base import PdoBase, PdoMaps

# Compatibility
from .base import Variable
Expand Down Expand Up @@ -38,7 +38,7 @@ class RPDO(PdoBase):

def __init__(self, node):
super(RPDO, self).__init__(node)
self.map = Maps(0x1400, 0x1600, self, 0x200)
self.map = PdoMaps(0x1400, 0x1600, self, 0x200)
logger.debug('RPDO Map as {0}'.format(len(self.map)))

def stop(self):
Expand All @@ -63,7 +63,7 @@ class TPDO(PdoBase):

def __init__(self, node):
super(TPDO, self).__init__(node)
self.map = Maps(0x1800, 0x1A00, self, 0x180)
self.map = PdoMaps(0x1800, 0x1A00, self, 0x180)
logger.debug('TPDO Map as {0}'.format(len(self.map)))

def stop(self):
Expand Down
21 changes: 13 additions & 8 deletions canopen/pdo/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class PdoBase(Mapping):

def __init__(self, node):
self.network = None
self.map = None # instance of Maps
self.map = None # instance of PdoMaps
self.node = node

def __iter__(self):
Expand Down Expand Up @@ -124,7 +124,7 @@ def stop(self):
pdo_map.stop()


class Maps(Mapping):
class PdoMaps(Mapping[int, "PdoMap"]):
"""A collection of transmit or receive maps."""

def __init__(self, com_offset, map_offset, pdo_node: PdoBase, cob_base=None):
Expand All @@ -134,10 +134,10 @@ def __init__(self, com_offset, map_offset, pdo_node: PdoBase, cob_base=None):
:param pdo_node:
:param cob_base:
"""
self.maps: Dict[int, "Map"] = {}
self.maps: Dict[int, "PdoMap"] = {}
for map_no in range(512):
if com_offset + map_no in pdo_node.node.object_dictionary:
new_map = Map(
new_map = PdoMap(
pdo_node,
pdo_node.node.sdo[com_offset + map_no],
pdo_node.node.sdo[map_offset + map_no])
Expand All @@ -146,7 +146,7 @@ def __init__(self, com_offset, map_offset, pdo_node: PdoBase, cob_base=None):
new_map.predefined_cob_id = cob_base + map_no * 0x100 + pdo_node.node.id
self.maps[map_no + 1] = new_map

def __getitem__(self, key: int) -> "Map":
def __getitem__(self, key: int) -> "PdoMap":
return self.maps[key]

def __iter__(self) -> Iterable[int]:
Expand All @@ -156,7 +156,7 @@ def __len__(self) -> int:
return len(self.maps)


class Map:
class PdoMap:
"""One message which can have up to 8 bytes of variables mapped."""

def __init__(self, pdo_node, com_record, map_array):
Expand Down Expand Up @@ -194,6 +194,9 @@ def __init__(self, pdo_node, com_record, map_array):
self.is_received: bool = False
self._task = None

def __repr__(self) -> str:
return f"<{type(self).__qualname__} '{self.name}' at COB-ID 0x{self.cob_id}>"

def __getitem_by_index(self, value):
valid_values = []
for var in self.map:
Expand Down Expand Up @@ -304,12 +307,12 @@ def on_message(self, can_id, data, timestamp):
for callback in self.callbacks:
callback(self)

def add_callback(self, callback: Callable[["Map"], None]) -> None:
def add_callback(self, callback: Callable[["PdoMap"], None]) -> None:
"""Add a callback which will be called on receive.

:param callback:
The function to call which must take one argument of a
:class:`~canopen.pdo.Map`.
:class:`~canopen.pdo.PdoMap`.
"""
self.callbacks.append(callback)

Expand Down Expand Up @@ -609,3 +612,5 @@ def set_data(self, data: bytes):

# For compatibility
Variable = PdoVariable
Maps = PdoMaps
Map = PdoMap
6 changes: 3 additions & 3 deletions canopen/profiles/p402.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ class BaseNode402(RemoteNode):
def __init__(self, node_id, object_dictionary):
super(BaseNode402, self).__init__(node_id, object_dictionary)
self.tpdo_values = {} # { index: value from last received TPDO }
self.tpdo_pointers = {} # { index: pdo.Map instance }
self.rpdo_pointers = {} # { index: pdo.Map instance }
self.tpdo_pointers = {} # { index: pdo.PdoMap instance }
self.rpdo_pointers = {} # { index: pdo.PdoMap instance }

def setup_402_state_machine(self, read_pdos=True):
"""Configure the state machine by searching for a TPDO that has the StatusWord mapped.
Expand Down Expand Up @@ -459,7 +459,7 @@ def on_TPDOs_update_callback(self, mapobject):
"""Cache updated values from a TPDO received from this node.

:param mapobject: The received PDO message.
:type mapobject: canopen.pdo.Map
:type mapobject: canopen.pdo.PdoMap
"""
for obj in mapobject:
self.tpdo_values[obj.index] = obj.raw
Expand Down
6 changes: 6 additions & 0 deletions canopen/sdo/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ def __init__(self, sdo_node: SdoBase, od: ObjectDictionary):
self.sdo_node = sdo_node
self.od = od

def __repr__(self) -> str:
return f"<{type(self).__qualname__} '{self.od.name}' at 0x{self.od.index:04x}>"

def __getitem__(self, subindex: Union[int, str]) -> "SdoVariable":
return SdoVariable(self.sdo_node, self.od[subindex])

Expand All @@ -118,6 +121,9 @@ def __init__(self, sdo_node: SdoBase, od: ObjectDictionary):
self.sdo_node = sdo_node
self.od = od

def __repr__(self) -> str:
return f"<{type(self).__qualname__} '{self.od.name}' at 0x{self.od.index:04x}>"

def __getitem__(self, subindex: Union[int, str]) -> "SdoVariable":
return SdoVariable(self.sdo_node, self.od[subindex])

Expand Down
6 changes: 6 additions & 0 deletions canopen/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ def __init__(self, od: objectdictionary.ODVariable):
#: Holds a local, overridable copy of the Object Subindex
self.subindex = od.subindex

def __repr__(self) -> str:
suffix = f":{self.subindex:02x}" if isinstance(self.od.parent,
(objectdictionary.ODRecord, objectdictionary.ODArray)
) else ""
return f"<{type(self).__qualname__} '{self.name}' at 0x{self.index:04x}{suffix}>"

def get_data(self) -> bytes:
raise NotImplementedError("Variable is not readable")

Expand Down
4 changes: 2 additions & 2 deletions doc/pdo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ API

.. describe:: pdo[no]

Return the :class:`canopen.pdo.Map` for the specified map number.
Return the :class:`canopen.pdo.PdoMap` for the specified map number.
First map starts at 1.

.. describe:: iter(pdo)
Expand All @@ -101,7 +101,7 @@ API
Return the number of supported maps.


.. autoclass:: canopen.pdo.Map
.. autoclass:: canopen.pdo.PdoMap
:members:

.. describe:: map[name]
Expand Down
Loading