diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5365620cd..aad9274fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,3 +87,25 @@ jobs: - name: Code Format Check with Black run: | black --check --verbose . + + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e .[canalystii,gs_usb] + pip install -r doc/doc-requirements.txt + - name: Build documentation + run: | + python -m sphinx -an doc build + - uses: actions/upload-artifact@v3 + with: + name: sphinx-out + path: ./build/ + retention-days: 5 diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 000000000..74cb9dbdd --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,31 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.10" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: doc/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +formats: + - pdf + - epub + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: doc/doc-requirements.txt + - method: pip + path: . + extra_requirements: + - canalystii + - gs_usb diff --git a/can/broadcastmanager.py b/can/broadcastmanager.py index c15186e2c..239d1d7d5 100644 --- a/can/broadcastmanager.py +++ b/can/broadcastmanager.py @@ -39,7 +39,7 @@ class CyclicTask(abc.ABC): def stop(self) -> None: """Cancel this periodic task. - :raises can.CanError: + :raises ~can.exceptions.CanError: If stop is called on an already stopped task. """ diff --git a/can/bus.py b/can/bus.py index b9ccfcfad..c0793c5f7 100644 --- a/can/bus.py +++ b/can/bus.py @@ -66,8 +66,10 @@ def __init__( Any backend dependent configurations are passed in this dictionary :raises ValueError: If parameters are out of range - :raises can.CanInterfaceNotImplementedError: If the driver cannot be accessed - :raises can.CanInitializationError: If the bus cannot be initialized + :raises ~can.exceptions.CanInterfaceNotImplementedError: + If the driver cannot be accessed + :raises ~can.exceptions.CanInitializationError: + If the bus cannot be initialized """ self._periodic_tasks: List[_SelfRemovingCyclicTask] = [] self.set_filters(can_filters) @@ -81,9 +83,11 @@ def recv(self, timeout: Optional[float] = None) -> Optional[Message]: :param timeout: seconds to wait for a message or None to wait indefinitely - :return: ``None`` on timeout or a :class:`Message` object. + :return: + :obj:`None` on timeout or a :class:`~can.Message` object. - :raises can.CanOperationError: If an error occurred while reading + :raises ~can.exceptions.CanOperationError: + If an error occurred while reading """ start = time() time_left = timeout @@ -148,7 +152,8 @@ def _recv_internal( 2. a bool that is True if message filtering has already been done and else False - :raises can.CanOperationError: If an error occurred while reading + :raises ~can.exceptions.CanOperationError: + If an error occurred while reading :raises NotImplementedError: if the bus provides it's own :meth:`~can.BusABC.recv` implementation (legacy implementation) @@ -171,7 +176,8 @@ def send(self, msg: Message, timeout: Optional[float] = None) -> None: Might not be supported by all interfaces. None blocks indefinitely. - :raises can.CanOperationError: If an error occurred while sending + :raises ~can.exceptions.CanOperationError: + If an error occurred while sending """ raise NotImplementedError("Trying to write to a readonly bus?") @@ -189,8 +195,8 @@ def send_periodic( - the (optional) duration expires - the Bus instance goes out of scope - the Bus instance is shutdown - - :meth:`BusABC.stop_all_periodic_tasks()` is called - - the task's :meth:`CyclicTask.stop()` method is called. + - :meth:`stop_all_periodic_tasks` is called + - the task's :meth:`~can.broadcastmanager.CyclicTask.stop` method is called. :param msgs: Message(s) to transmit @@ -204,7 +210,8 @@ def send_periodic( Disable to instead manage tasks manually. :return: A started task instance. Note the task can be stopped (and depending on - the backend modified) by calling the task's :meth:`stop` method. + the backend modified) by calling the task's + :meth:`~can.broadcastmanager.CyclicTask.stop` method. .. note:: @@ -274,8 +281,8 @@ def _send_periodic_internal( no duration is provided, the task will continue indefinitely. :return: A started task instance. Note the task can be stopped (and - depending on the backend modified) by calling the :meth:`stop` - method. + depending on the backend modified) by calling the + :meth:`~can.broadcastmanager.CyclicTask.stop` method. """ if not hasattr(self, "_lock_send_periodic"): # Create a send lock for this bus, but not for buses which override this method @@ -288,7 +295,7 @@ def _send_periodic_internal( return task def stop_all_periodic_tasks(self, remove_tasks: bool = True) -> None: - """Stop sending any messages that were started using **bus.send_periodic**. + """Stop sending any messages that were started using :meth:`send_periodic`. .. note:: The result is undefined if a single task throws an exception while being stopped. diff --git a/can/exceptions.py b/can/exceptions.py index 5a7aa0b7c..dc08be3b8 100644 --- a/can/exceptions.py +++ b/can/exceptions.py @@ -74,7 +74,7 @@ class CanInitializationError(CanError): """Indicates an error the occurred while initializing a :class:`can.BusABC`. If initialization fails due to a driver or platform missing/being unsupported, - a :class:`can.CanInterfaceNotImplementedError` is raised instead. + a :exc:`~can.exceptions.CanInterfaceNotImplementedError` is raised instead. If initialization fails due to a value being out of range, a :class:`ValueError` is raised. diff --git a/can/interfaces/ixxat/canlib_vcinpl.py b/can/interfaces/ixxat/canlib_vcinpl.py index cb0447b49..bdb05cda5 100644 --- a/can/interfaces/ixxat/canlib_vcinpl.py +++ b/can/interfaces/ixxat/canlib_vcinpl.py @@ -372,10 +372,8 @@ class IXXATBus(BusABC): .. warning:: This interface does implement efficient filtering of messages, but - the filters have to be set in :meth:`~can.interfaces.ixxat.IXXATBus.__init__` - using the ``can_filters`` parameter. Using :meth:`~can.interfaces.ixxat.IXXATBus.set_filters` - does not work. - + the filters have to be set in ``__init__`` using the ``can_filters`` parameter. + Using :meth:`~can.BusABC.set_filters` does not work. """ CHANNEL_BITRATES = { diff --git a/can/interfaces/ixxat/canlib_vcinpl2.py b/can/interfaces/ixxat/canlib_vcinpl2.py index 37085d74a..802168630 100644 --- a/can/interfaces/ixxat/canlib_vcinpl2.py +++ b/can/interfaces/ixxat/canlib_vcinpl2.py @@ -411,9 +411,8 @@ class IXXATBus(BusABC): .. warning:: This interface does implement efficient filtering of messages, but - the filters have to be set in :meth:`~can.interfaces.ixxat.IXXATBus.__init__` - using the ``can_filters`` parameter. Using :meth:`~can.interfaces.ixxat.IXXATBus.set_filters` - does not work. + the filters have to be set in ``__init__`` using the ``can_filters`` parameter. + Using :meth:`~can.BusABC.set_filters` does not work. """ diff --git a/can/interfaces/kvaser/canlib.py b/can/interfaces/kvaser/canlib.py index a951e39de..f60a43bc5 100644 --- a/can/interfaces/kvaser/canlib.py +++ b/can/interfaces/kvaser/canlib.py @@ -657,7 +657,7 @@ def shutdown(self): canBusOff(self._write_handle) canClose(self._write_handle) - def get_stats(self): + def get_stats(self) -> structures.BusStatistics: """Retrieves the bus statistics. Use like so: @@ -667,7 +667,6 @@ def get_stats(self): std_data: 0, std_remote: 0, ext_data: 0, ext_remote: 0, err_frame: 0, bus_load: 0.0%, overruns: 0 :returns: bus statistics. - :rtype: can.interfaces.kvaser.structures.BusStatistics """ canRequestBusStatistics(self._write_handle) stats = structures.BusStatistics() diff --git a/can/interfaces/kvaser/structures.py b/can/interfaces/kvaser/structures.py index c7d363dd4..996f16c37 100644 --- a/can/interfaces/kvaser/structures.py +++ b/can/interfaces/kvaser/structures.py @@ -7,11 +7,8 @@ class BusStatistics(ctypes.Structure): - """ - This structure is used with the method :meth:`KvaserBus.get_stats`. - - .. seealso:: :meth:`KvaserBus.get_stats` - + """This structure is used with the method + :meth:`~can.interfaces.kvaser.canlib.KvaserBus.get_stats`. """ _fields_ = [ diff --git a/can/interfaces/nican.py b/can/interfaces/nican.py index 0beeee429..ea13e28e8 100644 --- a/can/interfaces/nican.py +++ b/can/interfaces/nican.py @@ -179,10 +179,8 @@ class NicanBus(BusABC): .. warning:: This interface does implement efficient filtering of messages, but - the filters have to be set in :meth:`~can.interfaces.nican.NicanBus.__init__` - using the ``can_filters`` parameter. Using :meth:`~can.interfaces.nican.NicanBus.set_filters` - does not work. - + the filters have to be set in ``__init__`` using the ``can_filters`` parameter. + Using :meth:`~can.BusABC.set_filters` does not work. """ def __init__( @@ -208,9 +206,9 @@ def __init__( ``is_error_frame`` set to True and ``arbitration_id`` will identify the error (default True) - :raise can.CanInterfaceNotImplementedError: + :raise ~can.exceptions.CanInterfaceNotImplementedError: If the current operating system is not supported or the driver could not be loaded. - :raise can.interfaces.nican.NicanInitializationError: + :raise ~can.interfaces.nican.NicanInitializationError: If the bus could not be set up. """ if nican is None: diff --git a/can/interfaces/pcan/pcan.py b/can/interfaces/pcan/pcan.py index e5b877762..c60b9e6c9 100644 --- a/can/interfaces/pcan/pcan.py +++ b/can/interfaces/pcan/pcan.py @@ -113,8 +113,8 @@ def __init__( """A PCAN USB interface to CAN. On top of the usual :class:`~can.Bus` methods provided, - the PCAN interface includes the :meth:`~can.interface.pcan.PcanBus.flash` - and :meth:`~can.interface.pcan.PcanBus.status` methods. + the PCAN interface includes the :meth:`flash` + and :meth:`status` methods. :param str channel: The can interface name. An example would be 'PCAN_USBBUS1'. diff --git a/can/interfaces/robotell.py b/can/interfaces/robotell.py index 709fad78d..0d3ad1b77 100644 --- a/can/interfaces/robotell.py +++ b/can/interfaces/robotell.py @@ -5,9 +5,10 @@ import io import time import logging +from typing import Optional from can import BusABC, Message -from ..exceptions import CanInterfaceNotImplementedError +from ..exceptions import CanInterfaceNotImplementedError, CanOperationError logger = logging.getLogger(__name__) @@ -377,12 +378,11 @@ def fileno(self): except Exception as exception: raise CanOperationError("Cannot fetch fileno") from exception - def get_serial_number(self, timeout): + def get_serial_number(self, timeout: Optional[int]) -> Optional[str]: """Get serial number of the slcan interface. - :type timeout: int or None + :param timeout: seconds to wait for serial number or None to wait indefinitely - :rtype str or None :return: None on timeout or a str object. """ diff --git a/can/interfaces/serial/serial_can.py b/can/interfaces/serial/serial_can.py index ec4bb8671..c1507b4fa 100644 --- a/can/interfaces/serial/serial_can.py +++ b/can/interfaces/serial/serial_can.py @@ -74,8 +74,10 @@ def __init__( :param rtscts: turn hardware handshake (RTS/CTS) on and off - :raises can.CanInitializationError: If the given parameters are invalid. - :raises can.CanInterfaceNotImplementedError: If the serial module is not installed. + :raises ~can.exceptions.CanInitializationError: + If the given parameters are invalid. + :raises ~can.exceptions.CanInterfaceNotImplementedError: + If the serial module is not installed. """ if not serial: @@ -163,10 +165,10 @@ def _recv_internal( This parameter will be ignored. The timeout value of the channel is used. :returns: - Received message and `False` (because no filtering as taken place). + Received message and :obj:`False` (because no filtering as taken place). .. warning:: - Flags like is_extended_id, is_remote_frame and is_error_frame + Flags like ``is_extended_id``, ``is_remote_frame`` and ``is_error_frame`` will not be set over this function, the flags in the return message are the default values. """ diff --git a/can/interfaces/slcan.py b/can/interfaces/slcan.py index 63ea4ca42..212c4c85c 100644 --- a/can/interfaces/slcan.py +++ b/can/interfaces/slcan.py @@ -323,10 +323,10 @@ def get_serial_number(self, timeout: Optional[float]) -> Optional[str]: """Get serial number of the slcan interface. :param timeout: - seconds to wait for serial number or ``None`` to wait indefinitely + seconds to wait for serial number or :obj:`None` to wait indefinitely :return: - ``None`` on timeout or a :class:`~builtin.str` object. + :obj:`None` on timeout or a :class:`str` object. """ cmd = "N" self._write(cmd) diff --git a/can/interfaces/socketcan/socketcan.py b/can/interfaces/socketcan/socketcan.py index c7c038520..549998dc8 100644 --- a/can/interfaces/socketcan/socketcan.py +++ b/can/interfaces/socketcan/socketcan.py @@ -402,7 +402,7 @@ def stop(self) -> None: """Stop a task by sending TX_DELETE message to Linux kernel. This will delete the entry for the transmission of the CAN-message - with the specified :attr:`~task_id` identifier. The message length + with the specified ``task_id`` identifier. The message length for the command TX_DELETE is {[bcm_msg_head]} (only the header). """ log.debug("Stopping periodic task") @@ -444,7 +444,7 @@ def start(self) -> None: message to Linux kernel prior to scheduling. :raises ValueError: - If the task referenced by :attr:`~task_id` is already running. + If the task referenced by ``task_id`` is already running. """ self._tx_setup(self.messages) @@ -617,9 +617,10 @@ def __init__( If setting some socket options fails, an error will be printed but no exception will be thrown. This includes enabling: - - that own messages should be received, - - CAN-FD frames and - - error frames. + + - that own messages should be received, + - CAN-FD frames and + - error frames. :param channel: The can interface name with which to create this bus. @@ -739,7 +740,7 @@ def send(self, msg: Message, timeout: Optional[float] = None) -> None: Wait up to this many seconds for the transmit queue to be ready. If not given, the call may fail immediately. - :raises can.CanError: + :raises ~can.exceptions.CanError: if the message could not be written. """ log.debug("We've been asked to write a message to the bus") diff --git a/can/interfaces/systec/ucanbus.py b/can/interfaces/systec/ucanbus.py index 88224b856..fee110b08 100644 --- a/can/interfaces/systec/ucanbus.py +++ b/can/interfaces/systec/ucanbus.py @@ -88,10 +88,10 @@ def __init__(self, channel, can_filters=None, **kwargs): :raises ValueError: If invalid input parameter were passed. - :raises can.CanInterfaceNotImplementedError: + :raises ~can.exceptions.CanInterfaceNotImplementedError: If the platform is not supported. - :raises can.CanInitializationError: + :raises ~can.exceptions.CanInitializationError: If hardware or CAN interface initialization failed. """ try: @@ -181,7 +181,7 @@ def send(self, msg, timeout=None): :param float timeout: Transmit timeout in seconds (value 0 switches off the "auto delete") - :raises can.CanOperationError: + :raises ~can.exceptions.CanOperationError: If the message could not be sent. """ try: @@ -243,7 +243,7 @@ def flush_tx_buffer(self): """ Flushes the transmit buffer. - :raises can.CanError: + :raises ~can.exceptions.CanError: If flushing of the transmit buffer failed. """ log.info("Flushing transmit buffer") diff --git a/can/interfaces/usb2can/usb2canInterface.py b/can/interfaces/usb2can/usb2canInterface.py index e51d485cd..504b61c7b 100644 --- a/can/interfaces/usb2can/usb2canInterface.py +++ b/can/interfaces/usb2can/usb2canInterface.py @@ -67,22 +67,22 @@ class Usb2canBus(BusABC): This interface only works on Windows. Please use socketcan on Linux. - :param str channel (optional): + :param channel: The device's serial number. If not provided, Windows Management Instrumentation will be used to identify the first such device. - :param int bitrate (optional): + :param bitrate: Bitrate of channel in bit/s. Values will be limited to a maximum of 1000 Kb/s. Default is 500 Kbs - :param int flags (optional): + :param flags: Flags to directly pass to open function of the usb2can abstraction layer. - :param str dll (optional): + :param dll: Path to the DLL with the CANAL API to load Defaults to 'usb2can.dll' - :param str serial (optional): + :param serial: Alias for `channel` that is provided for legacy reasons. If both `serial` and `channel` are set, `serial` will be used and channel will be ignored. @@ -91,18 +91,19 @@ class Usb2canBus(BusABC): def __init__( self, - channel=None, - dll="usb2can.dll", - flags=0x00000008, + channel: Optional[str] = None, + dll: str = "usb2can.dll", + flags: int = 0x00000008, *_, - bitrate=500000, + bitrate: int = 500000, + serial: Optional[str] = None, **kwargs, ): self.can = Usb2CanAbstractionLayer(dll) # get the serial number of the device - device_id = kwargs.get("serial", channel) + device_id = serial or channel # search for a serial number if the device_id is None or empty if not device_id: diff --git a/can/interfaces/usb2can/usb2canabstractionlayer.py b/can/interfaces/usb2can/usb2canabstractionlayer.py index 8a3ae34ca..a6708cb42 100644 --- a/can/interfaces/usb2can/usb2canabstractionlayer.py +++ b/can/interfaces/usb2can/usb2canabstractionlayer.py @@ -9,6 +9,7 @@ import can from ...exceptions import error_check +from ...typechecking import StringPathLike log = logging.getLogger("can.usb2can") @@ -108,12 +109,13 @@ class Usb2CanAbstractionLayer: Documentation: http://www.8devices.com/media/products/usb2can/downloads/CANAL_API.pdf """ - def __init__(self, dll="usb2can.dll"): + def __init__(self, dll: StringPathLike = "usb2can.dll") -> None: """ - :type dll: str or path-like - :param dll (optional): the path to the usb2can DLL to load + :param dll: + the path to the usb2can DLL to load - :raises can.CanInterfaceNotImplementedError: if the DLL could not be loaded + :raises ~can.exceptions.CanInterfaceNotImplementedError: + if the DLL could not be loaded """ try: self.__m_dllBasic = windll.LoadLibrary(dll) @@ -128,11 +130,15 @@ def open(self, configuration: str, flags: int): """ Opens a CAN connection using `CanalOpen()`. - :param configuration: the configuration: "device_id; baudrate" - :param flags: the flags to be set + :param configuration: + the configuration: "device_id; baudrate" + :param flags: + the flags to be set + :returns: + Valid handle for CANAL API functions on success - :raises can.CanInitializationError: if any error occurred - :returns: Valid handle for CANAL API functions on success + :raises ~can.exceptions.CanInterfaceNotImplementedError: + if any error occurred """ try: # we need to convert this into bytes, since the underlying DLL cannot diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 7737a99d3..a36f67e9e 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -138,11 +138,11 @@ def __init__( :param tseg2_dbr: Bus timing value tseg2 (data) - :raise can.CanInterfaceNotImplementedError: + :raise ~can.exceptions.CanInterfaceNotImplementedError: If the current operating system is not supported or the driver could not be loaded. - :raise can.CanInitializationError: + :raise can.exceptions.CanInitializationError: If the bus could not be set up. - This may or may not be a :class:`can.interfaces.vector.VectorInitializationError`. + This may or may not be a :class:`~can.interfaces.vector.VectorInitializationError`. """ if os.name != "nt" and not kwargs.get("_testing", False): raise CanInterfaceNotImplementedError( diff --git a/can/interfaces/virtual.py b/can/interfaces/virtual.py index ffd5b0241..cc71469b5 100644 --- a/can/interfaces/virtual.py +++ b/can/interfaces/virtual.py @@ -40,7 +40,7 @@ class VirtualBus(BusABC): an identifier for connected buses. Implements :meth:`can.BusABC._detect_available_configs`; see - :meth:`can.VirtualBus._detect_available_configs` for how it + :meth:`_detect_available_configs` for how it behaves here. .. note:: @@ -84,7 +84,7 @@ def __init__( self.channel.append(self.queue) def _check_if_open(self) -> None: - """Raises :class:`~can.CanOperationError` if the bus is not open. + """Raises :exc:`~can.exceptions.CanOperationError` if the bus is not open. Has to be called in every method that accesses the bus. """ diff --git a/can/io/logger.py b/can/io/logger.py index ec34079b4..df13c6256 100644 --- a/can/io/logger.py +++ b/can/io/logger.py @@ -120,32 +120,31 @@ def on_message_received(self, msg: Message) -> None: class BaseRotatingLogger(Listener, BaseIOHandler, ABC): """ Base class for rotating CAN loggers. This class is not meant to be - instantiated directly. Subclasses must implement the :attr:`should_rollover` - and `do_rollover` methods according to their rotation strategy. + instantiated directly. Subclasses must implement the :meth:`should_rollover` + and :meth:`do_rollover` methods according to their rotation strategy. The rotation behavior can be further customized by the user by setting the :attr:`namer` and :attr:`rotator` attributes after instantiating the subclass. - These attributes as well as the methods `rotation_filename` and `rotate` + These attributes as well as the methods :meth:`rotation_filename` and :meth:`rotate` and the corresponding docstrings are carried over from the python builtin - `BaseRotatingHandler`. + :class:`~logging.handlers.BaseRotatingHandler`. Subclasses must set the `_writer` attribute upon initialization. - :attr namer: - If this attribute is set to a callable, the :meth:`rotation_filename` method - delegates to this callable. The parameters passed to the callable are - those passed to :meth:`rotation_filename`. - :attr rotator: - If this attribute is set to a callable, the :meth:`rotate` method delegates - to this callable. The parameters passed to the callable are those - passed to :meth:`rotate`. - :attr rollover_count: - An integer counter to track the number of rollovers. """ + #: If this attribute is set to a callable, the :meth:`~BaseRotatingLogger.rotation_filename` + #: method delegates to this callable. The parameters passed to the callable are + #: those passed to :meth:`~BaseRotatingLogger.rotation_filename`. namer: Optional[Callable[[StringPathLike], StringPathLike]] = None + + #: If this attribute is set to a callable, the :meth:`~BaseRotatingLogger.rotate` method + #: delegates to this callable. The parameters passed to the callable are those + #: passed to :meth:`~BaseRotatingLogger.rotate`. rotator: Optional[Callable[[StringPathLike, StringPathLike], None]] = None + + #: An integer counter to track the number of rollovers. rollover_count: int = 0 def __init__(self, *args: Any, **kwargs: Any) -> None: @@ -169,7 +168,7 @@ def rotation_filename(self, default_name: StringPathLike) -> StringPathLike: This is provided so that a custom filename can be provided. The default implementation calls the :attr:`namer` attribute of the handler, if it's callable, passing the default name to - it. If the attribute isn't callable (the default is `None`), the name + it. If the attribute isn't callable (the default is :obj:`None`), the name is returned unchanged. :param default_name: @@ -184,8 +183,8 @@ def rotate(self, source: StringPathLike, dest: StringPathLike) -> None: """When rotating, rotate the current log. The default implementation calls the :attr:`rotator` attribute of the - handler, if it's callable, passing the source and dest arguments to - it. If the attribute isn't callable (the default is `None`), the source + handler, if it's callable, passing the `source` and `dest` arguments to + it. If the attribute isn't callable (the default is :obj:`None`), the source is simply renamed to the destination. :param source: @@ -273,8 +272,10 @@ class SizedRotatingLogger(BaseRotatingLogger): by adding a timestamp and the rollover count. A new log file is then created and written to. - This behavior can be customized by setting the :attr:`namer` and - :attr:`rotator` attribute. + This behavior can be customized by setting the + :attr:`~can.io.BaseRotatingLogger.namer` and + :attr:`~can.io.BaseRotatingLogger.rotator` + attribute. Example:: diff --git a/can/io/sqlite.py b/can/io/sqlite.py index b9cbf9f93..0a4de85f2 100644 --- a/can/io/sqlite.py +++ b/can/io/sqlite.py @@ -25,7 +25,7 @@ class SqliteReader(MessageReader): This class can be iterated over or used to fetch all messages in the database with :meth:`~SqliteReader.read_all`. - Calling :func:`~builtin.len` on this object might not run in constant time. + Calling :func:`len` on this object might not run in constant time. :attr str table_name: the name of the database table used for storing the messages diff --git a/can/message.py b/can/message.py index 87cb6a199..8e0c4deee 100644 --- a/can/message.py +++ b/can/message.py @@ -29,7 +29,7 @@ class Message: # pylint: disable=too-many-instance-attributes; OK for a datacla :func:`~copy.copy`/:func:`~copy.deepcopy` is supported as well. Messages do not support "dynamic" attributes, meaning any others than the - documented ones, since it uses :attr:`~object.__slots__`. + documented ones, since it uses :obj:`~object.__slots__`. """ __slots__ = ( diff --git a/can/typechecking.py b/can/typechecking.py index ed76b6c85..b3a513a3a 100644 --- a/can/typechecking.py +++ b/can/typechecking.py @@ -8,7 +8,9 @@ import typing_extensions -CanFilter = typing_extensions.TypedDict("CanFilter", {"can_id": int, "can_mask": int}) +CanFilter: typing_extensions = typing_extensions.TypedDict( + "CanFilter", {"can_id": int, "can_mask": int} +) CanFilterExtended = typing_extensions.TypedDict( "CanFilterExtended", {"can_id": int, "can_mask": int, "extended": bool} ) diff --git a/can/util.py b/can/util.py index d1ff643de..e64eb13b5 100644 --- a/can/util.py +++ b/can/util.py @@ -258,8 +258,10 @@ def _create_bus_config(config: Dict[str, Any]) -> typechecking.BusConfig: def set_logging_level(level_name: str) -> None: """Set the logging level for the `"can"` logger. - :param level_name: One of: `'critical'`, `'error'`, `'warning'`, `'info'`, - `'debug'`, `'subdebug'`, or the value `None` (=default). Defaults to `'debug'`. + :param level_name: + One of: `'critical'`, `'error'`, `'warning'`, `'info'`, + `'debug'`, `'subdebug'`, or the value :obj:`None` (=default). + Defaults to `'debug'`. """ can_logger = logging.getLogger("can") @@ -316,7 +318,7 @@ def deprecated_args_alias(**aliases): """Allows to rename/deprecate a function kwarg(s) and optionally have the deprecated kwarg(s) set as alias(es) - Example: + Example:: @deprecated_args_alias(oldArg="new_arg", anotherOldArg="another_new_arg") def library_function(new_arg, another_new_arg): @@ -325,6 +327,7 @@ def library_function(new_arg, another_new_arg): @deprecated_args_alias(oldArg="new_arg", obsoleteOldArg=None) def library_function(new_arg): pass + """ def deco(f): diff --git a/doc/bcm.rst b/doc/bcm.rst index 549b06edd..94cde0e60 100644 --- a/doc/bcm.rst +++ b/doc/bcm.rst @@ -42,3 +42,7 @@ which inherits from :class:`~can.broadcastmanager.CyclicTask`. .. autoclass:: can.RestartableCyclicTaskABC :members: + +.. autoclass:: can.broadcastmanager.ThreadBasedCyclicSendTask + :members: + diff --git a/doc/bus.rst b/doc/bus.rst index bbe52cbd6..9f7077cc1 100644 --- a/doc/bus.rst +++ b/doc/bus.rst @@ -20,7 +20,6 @@ Autoconfig Bus .. autoclass:: can.Bus :members: - :undoc-members: API @@ -28,9 +27,17 @@ API .. autoclass:: can.BusABC :members: - :undoc-members: .. automethod:: __iter__ + .. automethod:: _recv_internal + .. automethod:: _apply_filters + .. automethod:: _detect_available_configs + .. automethod:: _send_periodic_internal + +.. autoclass:: can.bus.BusState + :members: + :undoc-members: + Transmitting '''''''''''' diff --git a/doc/conf.py b/doc/conf.py index 14390d5ad..495416078 100755 --- a/doc/conf.py +++ b/doc/conf.py @@ -8,6 +8,8 @@ import sys import os +import ctypes +from unittest.mock import MagicMock # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -15,6 +17,7 @@ sys.path.insert(0, os.path.abspath("..")) import can # pylint: disable=wrong-import-position +from can import ctypesutil # -- General configuration ----------------------------------------------------- @@ -45,11 +48,11 @@ "sphinx.ext.viewcode", "sphinx.ext.graphviz", "sphinxcontrib.programoutput", - "sphinx_autodoc_typehints", + "sphinx_rtd_theme", ] # Now, you can use the alias name as a new role, e.g. :issue:`123`. -extlinks = {"issue": ("https://github.com/hardbyte/python-can/issues/%s/", "issue ")} +extlinks = {"issue": ("https://github.com/hardbyte/python-can/issues/%s/", "issue #%s")} intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)} @@ -111,11 +114,31 @@ # Keep cached intersphinx inventories indefinitely intersphinx_cache_limit = -1 +# location of typehints +autodoc_typehints = "description" + +# disable specific warnings +nitpick_ignore = [ + # Ignore warnings for type aliases. Remove once Sphinx supports PEP613 + ("py:class", "can.typechecking.BusConfig"), + ("py:class", "can.typechecking.CanFilter"), + ("py:class", "can.typechecking.CanFilterExtended"), + ("py:class", "can.typechecking.AutoDetectedConfig"), + # intersphinx fails to reference some builtins + ("py:class", "asyncio.events.AbstractEventLoop"), + ("py:class", "_thread.allocate_lock"), +] + +# mock windows specific attributes +autodoc_mock_imports = ["win32com"] +ctypes.windll = MagicMock() +ctypesutil.HRESULT = ctypes.c_long + # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "default" +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/doc/doc-requirements.txt b/doc/doc-requirements.txt index dead5e2e5..9732ea4ef 100644 --- a/doc/doc-requirements.txt +++ b/doc/doc-requirements.txt @@ -1,3 +1,3 @@ -sphinx>=1.8.1 +sphinx>=5.2.3 sphinxcontrib-programoutput -sphinx-autodoc-typehints +sphinx_rtd_theme diff --git a/doc/interfaces.rst b/doc/interfaces.rst index 757cf67b4..dbe4ad426 100644 --- a/doc/interfaces.rst +++ b/doc/interfaces.rst @@ -26,6 +26,7 @@ The available interfaces are: interfaces/serial interfaces/slcan interfaces/socketcan + interfaces/socketcand interfaces/systec interfaces/udp_multicast interfaces/usb2can diff --git a/doc/interfaces/etas.rst b/doc/interfaces/etas.rst index cc3cbdea4..2b59a4eee 100644 --- a/doc/interfaces/etas.rst +++ b/doc/interfaces/etas.rst @@ -6,7 +6,7 @@ The ETAS BOA_ (Basic Open API) is used. Install the "ETAS ECU and Bus Interfaces – Distribution Package". Only Windows is supported by this interface. The Linux kernel v5.13 (and greater) natively supports ETAS ES581.4, ES582.1 and ES584.1 USB modules. -To use these under Linux, please refer to :ref:`socketcan`. +To use these under Linux, please refer to :ref:`SocketCAN`. Bus --- @@ -25,7 +25,7 @@ The simplest configuration file would be:: Channels are the URIs used by the underlying API. -To find available URIs, use :meth:`~can.interface.detect_available_configs`:: +To find available URIs, use :meth:`~can.detect_available_configs`:: configs = can.interface.detect_available_configs(interfaces="etas") for c in configs: diff --git a/doc/interfaces/ixxat.rst b/doc/interfaces/ixxat.rst index 28fb6f314..02e707c1c 100644 --- a/doc/interfaces/ixxat.rst +++ b/doc/interfaces/ixxat.rst @@ -8,7 +8,7 @@ Interface to `IXXAT `__ Virtual CAN Interface V3 SDK. Wor The Linux ECI SDK is currently unsupported, however on Linux some devices are supported with :doc:`socketcan`. -The :meth:`~can.interfaces.ixxat.canlib.IXXATBus.send_periodic` method is supported +The :meth:`~can.BusABC.send_periodic` method is supported natively through the on-board cyclic transmit list. Modifying cyclic messages is not possible. You will need to stop it, and then start a new periodic message. @@ -20,7 +20,22 @@ Bus .. autoclass:: can.interfaces.ixxat.IXXATBus :members: -.. autoclass:: can.interfaces.ixxat.canlib.CyclicSendTask +Implementation based on vcinpl.dll +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: can.interfaces.ixxat.canlib_vcinpl.IXXATBus + :members: + +.. autoclass:: can.interfaces.ixxat.canlib_vcinpl.CyclicSendTask + :members: + +Implementation based on vcinpl2.dll +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: can.interfaces.ixxat.canlib_vcinpl2.IXXATBus + :members: + +.. autoclass:: can.interfaces.ixxat.canlib_vcinpl2.CyclicSendTask :members: diff --git a/doc/interfaces/kvaser.rst b/doc/interfaces/kvaser.rst index a4a51ad09..4e0062cfa 100644 --- a/doc/interfaces/kvaser.rst +++ b/doc/interfaces/kvaser.rst @@ -46,3 +46,5 @@ This section contains Kvaser driver specific methods. .. automethod:: can.interfaces.kvaser.canlib.KvaserBus.get_stats +.. autoclass:: can.interfaces.kvaser.structures.BusStatistics + :members: diff --git a/doc/interfaces/neovi.rst b/doc/interfaces/neovi.rst index 05423ac8e..588c5e914 100644 --- a/doc/interfaces/neovi.rst +++ b/doc/interfaces/neovi.rst @@ -42,5 +42,6 @@ Bus --- .. autoclass:: can.interfaces.ics_neovi.NeoViBus - - +.. autoexception:: can.interfaces.ics_neovi.ICSApiError +.. autoexception:: can.interfaces.ics_neovi.ICSInitializationError +.. autoexception:: can.interfaces.ics_neovi.ICSOperationError diff --git a/doc/interfaces/nican.rst b/doc/interfaces/nican.rst index b2214371f..4d2a40717 100644 --- a/doc/interfaces/nican.rst +++ b/doc/interfaces/nican.rst @@ -21,6 +21,7 @@ Bus .. autoclass:: can.interfaces.nican.NicanBus .. autoexception:: can.interfaces.nican.NicanError +.. autoexception:: can.interfaces.nican.NicanInitializationError .. _National Instruments: http://www.ni.com/can/ diff --git a/doc/interfaces/pcan.rst b/doc/interfaces/pcan.rst index ff82ba9f4..feb40b195 100644 --- a/doc/interfaces/pcan.rst +++ b/doc/interfaces/pcan.rst @@ -48,3 +48,4 @@ Bus --- .. autoclass:: can.interfaces.pcan.PcanBus + :members: diff --git a/doc/interfaces/seeedstudio.rst b/doc/interfaces/seeedstudio.rst index 5c86fa688..da4d86995 100644 --- a/doc/interfaces/seeedstudio.rst +++ b/doc/interfaces/seeedstudio.rst @@ -1,9 +1,8 @@ .. _seeeddoc: -USB-CAN Analyzer -================ -...by Seeed Studio +Seeed Studio USB-CAN Analyzer +============================= SKU: 114991193 diff --git a/doc/interfaces/serial.rst b/doc/interfaces/serial.rst index 59ffef21a..99ee54df6 100644 --- a/doc/interfaces/serial.rst +++ b/doc/interfaces/serial.rst @@ -21,6 +21,8 @@ Bus .. autoclass:: can.interfaces.serial.serial_can.SerialBus + .. automethod:: _recv_internal + Internals --------- The frames that will be sent and received over the serial interface consist of diff --git a/doc/interfaces/socketcan.rst b/doc/interfaces/socketcan.rst index 1e82d8827..f6cc1ba5f 100644 --- a/doc/interfaces/socketcan.rst +++ b/doc/interfaces/socketcan.rst @@ -1,7 +1,9 @@ +.. _SocketCAN: + SocketCAN ========= -The `SocketCAN`_ documentation can be found in the Linux kernel docs at +The SocketCAN documentation can be found in the `Linux kernel docs`_ at ``networking`` directory. Quoting from the SocketCAN Linux documentation:: > The socketcan package is an implementation of CAN protocols @@ -284,7 +286,7 @@ to ensure usage of SocketCAN Linux API. The most important differences are: .. External references -.. _SocketCAN: https://www.kernel.org/doc/Documentation/networking/can.txt +.. _Linux kernel docs: https://www.kernel.org/doc/Documentation/networking/can.txt .. _Intrepid kernel module: https://github.com/intrepidcs/intrepid-socketcan-kernel-module .. _Intrepid user-space daemon: https://github.com/intrepidcs/icsscand .. _can-utils: https://github.com/linux-can/can-utils diff --git a/doc/interfaces/socketcand.rst b/doc/interfaces/socketcand.rst index e50f134e1..3c05bcc85 100644 --- a/doc/interfaces/socketcand.rst +++ b/doc/interfaces/socketcand.rst @@ -28,8 +28,8 @@ daemon running on a remote Raspberry Pi: except KeyboardInterrupt: pass -The output may look like this: -:: +The output may look like this:: + Timestamp: 1637791111.209224 ID: 000006fd X Rx DLC: 8 c4 10 e3 2d 96 ff 25 6b Timestamp: 1637791111.233951 ID: 000001ad X Rx DLC: 4 4d 47 c7 64 Timestamp: 1637791111.409415 ID: 000005f7 X Rx DLC: 8 86 de e6 0f 42 55 5d 39 @@ -47,8 +47,9 @@ However, it will also work with any other socketcan device. Install CAN Interface for a MCP2515 based interface on a Raspberry Pi ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Add the following lines to ``/boot/config.txt``. Please take care on the frequency of the crystal on your MCP2515 board: -:: +Add the following lines to ``/boot/config.txt``. +Please take care on the frequency of the crystal on your MCP2515 board:: + dtparam=spi=on dtoverlay=mcp2515-can0,oscillator=12000000,interrupt=25,spimaxfrequency=1000000 @@ -106,8 +107,8 @@ Run socketcand ./socketcand -v -i can0 -During start, socketcand will prompt its IP address and port it listens to: -:: +During start, socketcand will prompt its IP address and port it listens to:: + Verbose output activated Using network interface 'eth0' diff --git a/doc/interfaces/usb2can.rst b/doc/interfaces/usb2can.rst index e2e8d7517..56243d41d 100644 --- a/doc/interfaces/usb2can.rst +++ b/doc/interfaces/usb2can.rst @@ -86,3 +86,5 @@ Internals .. autoclass:: can.interfaces.usb2can.Usb2CanAbstractionLayer :members: :undoc-members: + +.. autoexception:: can.interfaces.usb2can.usb2canabstractionlayer.CanalError diff --git a/doc/interfaces/vector.rst b/doc/interfaces/vector.rst index dcd45f1bf..7b5ede616 100644 --- a/doc/interfaces/vector.rst +++ b/doc/interfaces/vector.rst @@ -19,8 +19,6 @@ application named "python-can":: channel = 0, 1 app_name = python-can -If you are using Python 2.7 it is recommended to install pywin32_, otherwise a -slow and CPU intensive polling will be used when waiting for new messages. Bus @@ -29,7 +27,7 @@ Bus .. autoclass:: can.interfaces.vector.VectorBus .. autoexception:: can.interfaces.vector.VectorError - +.. autoexception:: can.interfaces.vector.VectorInitializationError +.. autoexception:: can.interfaces.vector.VectorOperationError .. _Vector: https://vector.com/ -.. _pywin32: https://sourceforge.net/projects/pywin32/ diff --git a/doc/interfaces/virtual.rst b/doc/interfaces/virtual.rst index 9258c9bbd..29976ed47 100644 --- a/doc/interfaces/virtual.rst +++ b/doc/interfaces/virtual.rst @@ -70,8 +70,8 @@ arrive at the recipients exactly once. Both is not guaranteed to hold for the be these guarantees of message delivery and message ordering. The central servers receive and distribute the CAN messages to all other bus participants, unlike in a real physical CAN network. The first intra-process ``virtual`` interface only runs within one Python process, effectively the -Python instance of :class:`VirtualBus` acts as a central server. Notably the ``udp_multicast`` bus -does not require a central server. +Python instance of :class:`~can.interfaces.virtual.VirtualBus` acts as a central server. +Notably the ``udp_multicast`` bus does not require a central server. **Arbitration and throughput** are two interrelated functions/properties of CAN networks which are typically abstracted in virtual interfaces. In all four interfaces, an unlimited amount @@ -133,3 +133,5 @@ Bus Class Documentation .. autoclass:: can.interfaces.virtual.VirtualBus :members: + + .. automethod:: _detect_available_configs diff --git a/doc/internal-api.rst b/doc/internal-api.rst index c43db3394..1367dca50 100644 --- a/doc/internal-api.rst +++ b/doc/internal-api.rst @@ -70,7 +70,7 @@ methods: About the IO module ------------------- -Handling of the different file formats is implemented in :mod:`can.io`. +Handling of the different file formats is implemented in ``can.io``. Each file/IO type is within a separate module and ideally implements both a *Reader* and a *Writer*. The reader usually extends :class:`can.io.generic.BaseIOHandler`, while the writer often additionally extends :class:`can.Listener`, diff --git a/doc/message.rst b/doc/message.rst index e5745f6b5..78ccc0b50 100644 --- a/doc/message.rst +++ b/doc/message.rst @@ -200,3 +200,5 @@ Message Each of the bytes in the data field (when present) are represented as two-digit hexadecimal numbers. + + .. automethod:: equals diff --git a/doc/scripts.rst b/doc/scripts.rst index ace8c1e39..6b9bdf504 100644 --- a/doc/scripts.rst +++ b/doc/scripts.rst @@ -55,6 +55,6 @@ The full usage page can be seen below: can.logconvert ----------- +-------------- .. command-output:: python -m can.logconvert -h diff --git a/setup.cfg b/setup.cfg index b402ee645..043fff73a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,6 +12,7 @@ warn_unused_ignores = True exclude = (?x)( venv + |^doc/conf.py$ |^test |^setup.py$ |^can/interfaces/__init__.py