Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions doc/API/error.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Errors
======

.. automodule:: snap7.error
:members:
14 changes: 13 additions & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,19 @@

# -- General configuration -----------------------------------------------------

extensions = ["sphinx.ext.autodoc", "sphinx.ext.coverage", "sphinx.ext.viewcode", "sphinx.ext.napoleon"]
extensions = ["sphinx.ext.autodoc", "sphinx.ext.coverage", "sphinx.ext.viewcode", "sphinx.ext.napoleon", "sphinx.ext.intersphinx"]

intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
}

nitpick_ignore = [
("py:class", "ctypes.Array"),
("py:class", "ctypes.c_int"),
("py:class", "ctypes.c_uint"),
("py:class", "snap7.type.S7DataItem"),
("py:class", "snap7.type.c_ubyte_Array_65536"),
]

templates_path = ["_templates"]

Expand Down
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Welcome to python-snap7's documentation!
API/optimizer
API/log
API/type
API/error

.. toctree::
:maxdepth: 2
Expand Down
2 changes: 1 addition & 1 deletion s7commplus/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ async def browse(self) -> list[dict[str, Any]]:
.. warning:: This method is **experimental** and may change.

Returns a flat list of variable dicts with keys ``name``, ``access_sequence``
(the dot-separated hex LID path usable with :meth:`read_tag`), ``data_type``,
(the dot-separated hex LID path usable with ``read_tag()``), ``data_type``,
and the optimized/non-optimized byte+bit offsets. Steps: enumerate DBs, resolve
each DB's type-info RID via a LID=1 read, explore the OMS type-info container,
then recombine into the symbol tree.
Expand Down
4 changes: 2 additions & 2 deletions s7commplus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ def browse(self) -> list[dict[str, Any]]:
.. warning:: This method is **experimental** and may change.

Returns a flat list of variable dicts with keys ``name``, ``access_sequence``
(the dot-separated hex LID path usable with :meth:`read_tag`), ``data_type``,
(the dot-separated hex LID path usable with ``read_tag()``), ``data_type``,
and the optimized/non-optimized byte+bit offsets. Steps: enumerate DBs, resolve
each DB's type-info RID via a LID=1 read, explore the OMS type-info container,
then recombine into the symbol tree.
Expand Down Expand Up @@ -477,7 +477,7 @@ def create_subscription(self, items: list[tuple[int, int, int]], cycle_ms: int =
.. warning:: This method is **experimental** and may change.

The PLC will push data updates for the specified variables. Use
:meth:`receive_notification` to receive the pushed data.
``receive_notification()`` to receive the pushed data.

Args:
items: List of (db_number, start_offset, size) tuples to monitor.
Expand Down
4 changes: 2 additions & 2 deletions snap7/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Uses asyncio streams for non-blocking I/O with an asyncio.Lock() to serialize
send/receive cycles, ensuring safe concurrent use via asyncio.gather().

For new projects, use :class:`s7.AsyncClient` instead, which supports all PLC
For new projects, use ``s7.AsyncClient`` instead, which supports all PLC
models and automatically selects the best protocol.
"""

Expand Down Expand Up @@ -287,7 +287,7 @@ class AsyncClient(ClientMixin):
serializes each send+receive cycle so that concurrent coroutines
(e.g. via asyncio.gather) never interleave on the same TCP socket.

For new projects, use :class:`s7.AsyncClient` instead.
For new projects, use ``s7.AsyncClient`` instead.

Examples:
>>> from s7 import AsyncClient
Expand Down
14 changes: 7 additions & 7 deletions snap7/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Legacy S7 client implementation.

Pure Python implementation of the classic S7 protocol. For new projects,
use :class:`s7.Client` instead, which supports all PLC models and
use ``s7.Client`` instead, which supports all PLC models and
automatically selects the best protocol.
"""

Expand Down Expand Up @@ -247,7 +247,7 @@ class Client(ClientMixin):
Legacy S7 client for classic PUT/GET communication.

Supports S7-300, S7-400, S7-1200 and S7-1500 PLCs via the classic S7
protocol. For new projects, use :class:`s7.Client` instead, which
protocol. For new projects, use ``s7.Client`` instead, which
automatically selects the best protocol for any supported PLC.

Examples:
Expand Down Expand Up @@ -784,13 +784,13 @@ def db_write_array(self, db_number: int, start: int, values: list[Any], fmt: str
return self.db_write(db_number, start, data)

def read_tag(self, tag: "Union[Tag, str]") -> Any:
"""Read a typed value by :class:`Tag` or address string.
"""Read a typed value by :class:`~snap7.tags.Tag` or address string.

Accepts a :class:`~snap7.tags.Tag` or a PLC4X-style address string
(e.g. ``"DB1.DBX0.0:BOOL"``, ``"DB1:10:INT"``, ``"M10.5:BOOL"``).

Args:
tag: A :class:`Tag` instance or a parseable address string.
tag: A :class:`~snap7.tags.Tag` instance or a parseable address string.

Returns:
The typed value (bool/int/float/datetime/str depending on type).
Expand All @@ -811,10 +811,10 @@ def read_tag(self, tag: "Union[Tag, str]") -> Any:
return _decode_tag(resolved, bytearray(data))

def write_tag(self, tag: "Union[Tag, str]", value: Any) -> int:
"""Write a typed value by :class:`Tag` or address string.
"""Write a typed value by :class:`~snap7.tags.Tag` or address string.

Args:
tag: A :class:`Tag` instance or a parseable address string.
tag: A :class:`~snap7.tags.Tag` instance or a parseable address string.
value: The value to write (type must match the tag's datatype).

Returns:
Expand All @@ -841,7 +841,7 @@ def read_tags(self, tags: "list[Union[Tag, str]]") -> list[Any]:
reads into minimal PDU exchanges.

Args:
tags: List of :class:`Tag` instances or address strings.
tags: List of :class:`~snap7.tags.Tag` instances or address strings.

Returns:
List of decoded values in the same order as input.
Expand Down
18 changes: 9 additions & 9 deletions snap7/s7protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ def validate_pdu_reference(self, response_sequence: int) -> None:
response_sequence: Sequence number from the response PDU.

Raises:
S7StalePacketError: If response is older than expected (stale).
S7PacketLostError: If response is ahead of expected (packet loss).
~snap7.error.S7StalePacketError: If response is older than expected (stale).
~snap7.error.S7PacketLostError: If response is ahead of expected (packet loss).
"""
if response_sequence < self.sequence:
raise S7StalePacketError(f"Stale packet: expected sequence {self.sequence}, got {response_sequence}")
Expand Down Expand Up @@ -239,7 +239,7 @@ def extract_multi_read_data(self, response: Dict[str, Any], block_count: int) ->
List of bytearrays, one per block.

Raises:
S7ProtocolError: If any item has a non-success return code.
~snap7.error.S7ProtocolError: If any item has a non-success return code.
"""
raw = response.get("raw_data", b"")
if not raw:
Expand Down Expand Up @@ -429,7 +429,7 @@ def check_control_response(self, response: Dict[str, Any]) -> None:
response: Parsed S7 response

Raises:
S7ProtocolError: If control operation failed
~snap7.error.S7ProtocolError: If control operation failed
"""
# For now, just check that we got a response
# In a full implementation, we would check specific error codes
Expand Down Expand Up @@ -1048,15 +1048,15 @@ def parse_get_block_info_response(self, response: Dict[str, Any]) -> Dict[str, A
return result

def parse_list_blocks(self, response: Dict[str, Any]) -> BlocksList:
"""Parse list blocks response directly into a :class:`BlocksList`.
"""Parse list blocks response directly into a :class:`~snap7.type.BlocksList`.

Consolidates the dict→struct conversion that used to live in both
the sync and async clients so the field mapping is declared once.
"""
return build_blocks_list_from_dict(self.parse_list_blocks_response(response))

def parse_get_block_info(self, response: Dict[str, Any]) -> TS7BlockInfo:
"""Parse block info response directly into a :class:`TS7BlockInfo`.
"""Parse block info response directly into a :class:`~snap7.type.TS7BlockInfo`.

Consolidates the dict→struct conversion that used to live in both
the sync and async clients.
Expand Down Expand Up @@ -1602,7 +1602,7 @@ def check_write_response(self, response: Dict[str, Any]) -> None:
response: Parsed S7 response

Raises:
S7ProtocolError: If write operation failed
~snap7.error.S7ProtocolError: If write operation failed
"""
# First check for errors in the response header
# S7-1200/1500 returns error codes in the header for write failures
Expand Down Expand Up @@ -1631,7 +1631,7 @@ def check_write_response(self, response: Dict[str, Any]) -> None:


def build_blocks_list_from_dict(counts: Dict[str, int]) -> BlocksList:
"""Populate a :class:`BlocksList` from the dict returned by ``parse_list_blocks_response``."""
"""Populate a :class:`~snap7.type.BlocksList` from the dict returned by ``parse_list_blocks_response``."""
block_list = BlocksList()
block_list.OBCount = counts.get("OBCount", 0)
block_list.FBCount = counts.get("FBCount", 0)
Expand All @@ -1644,7 +1644,7 @@ def build_blocks_list_from_dict(counts: Dict[str, int]) -> BlocksList:


def build_block_info_from_dict(info: Dict[str, Any]) -> TS7BlockInfo:
"""Populate a :class:`TS7BlockInfo` from the dict returned by ``parse_get_block_info_response``."""
"""Populate a :class:`~snap7.type.TS7BlockInfo` from the dict returned by ``parse_get_block_info_response``."""
block_info = TS7BlockInfo()
block_info.BlkType = info["block_type"]
block_info.BlkNumber = info["block_number"]
Expand Down
4 changes: 2 additions & 2 deletions snap7/server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Legacy S7 server implementation.

Provides a complete S7 server emulator for the classic S7 protocol. For new
projects, use :class:`s7.Server` instead, which supports both legacy S7 and
projects, use ``s7.Server`` instead, which supports both legacy S7 and
S7CommPlus clients.
"""

Expand Down Expand Up @@ -46,7 +46,7 @@ class Server:
Legacy S7 server implementation.

Emulates a Siemens S7 PLC for testing and development purposes.
For new projects, use :class:`s7.Server` instead.
For new projects, use ``s7.Server`` instead.

Examples:
>>> from s7 import Server
Expand Down
2 changes: 1 addition & 1 deletion snap7/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ def load_json(source: Union[str, Path]) -> dict[str, Tag]:


def from_browse(variables: list[dict[str, Any]]) -> dict[str, Tag]:
"""Build a dict of Tags from :meth:`s7.Client.browse` results.
"""Build a dict of Tags from ``Client.browse()`` results.

.. warning:: This function is **experimental** and may change.

Expand Down
9 changes: 5 additions & 4 deletions snap7/util/setters.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ def set_fstring(bytearray_: Buffer, byte_index: int, value: str, max_length: int

Raises:
:obj:`TypeError`: if the `value` is not a :obj:`str`.
:obj:`ValueError`: if the length of the `value` is larger than the `max_size`
or 'value' contains non-ascii characters.
:obj:`ValueError`: if the length of the `value` is larger than the
``max_size`` or ``value`` contains non-ASCII characters.

Examples:
>>> data = bytearray(20)
Expand Down Expand Up @@ -208,8 +208,9 @@ def set_string(bytearray_: Buffer, byte_index: int, value: str, max_size: int =

Raises:
:obj:`TypeError`: if the `value` is not a :obj:`str`.
:obj:`ValueError`: if the length of the `value` is larger than the `max_size`
or 'max_size' is greater than 254 or 'value' contains ascii characters > 255.
:obj:`ValueError`: if the length of the `value` is larger than the
``max_size``, or ``max_size`` is greater than 254, or ``value``
contains characters with ordinal > 255.

Examples:
>>> from snap7.util import set_string
Expand Down
Loading