FYI: Multi-read optimization integrated into upstream python-snap7#1
Open
gijzelaerr wants to merge 48 commits intoQuakeString:masterfrom
Open
FYI: Multi-read optimization integrated into upstream python-snap7#1gijzelaerr wants to merge 48 commits intoQuakeString:masterfrom
gijzelaerr wants to merge 48 commits intoQuakeString:masterfrom
Conversation
Bumps the all-dependencies group with 4 updates: [ruff](https://github.com/astral-sh/ruff), [tox](https://github.com/tox-dev/tox), [tox-uv](https://github.com/tox-dev/tox-uv) and [uv](https://github.com/astral-sh/uv). Updates `ruff` from 0.15.5 to 0.15.6 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.5...0.15.6) Updates `tox` from 4.49.0 to 4.49.1 - [Release notes](https://github.com/tox-dev/tox/releases) - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - [Commits](tox-dev/tox@4.49.0...4.49.1) Updates `tox-uv` from 1.33.1 to 1.33.4 - [Release notes](https://github.com/tox-dev/tox-uv/releases) - [Commits](tox-dev/tox-uv@1.33.1...1.33.4) Updates `uv` from 0.10.9 to 0.10.10 - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](astral-sh/uv@0.10.9...0.10.10) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies - dependency-name: tox dependency-version: 4.49.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies - dependency-name: tox-uv dependency-version: 1.33.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies - dependency-name: uv dependency-version: 0.10.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Strengthen messaging around the pure Python rewrite: emphasize that 3.0 completely breaks with the C snap7 shared library wrapper approach, highlight improved portability and easier installation, and add clear guidance for reporting issues and falling back to pre-3.0 releases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The library no longer wraps the C snap7 library as of 3.0, but the name is kept for backwards compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add coverage badge and coverage threshold - Replace artifact upload with codecov/codecov-action@v5 in test workflow - Add codecov badge to README.rst - Add coverage threshold of 80% in pyproject.toml and codecov.yml Closes #619 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Lower coverage threshold to 75% to match current coverage Current coverage is 78% — set threshold to 75% to provide a safety net without failing CI. Can be raised as coverage improves. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add project badges to README Add PyPI version, Python versions, license, CI status, and Read the Docs badges alongside the existing Codecov badge for a professional landing page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Don't fail CI when Codecov upload fails Codecov v5 requires a token for protected branches, causing "Token required because branch is protected" errors that block CI. Coverage upload is best-effort, not a gate. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add 55 tests covering PDU building/parsing, lifecycle management, send/recv buffers, parameters, and dual-partner data exchange via socket pairs. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The setter functions already worked with memoryview at runtime (using direct struct.pack() slice assignment), but the type annotations only accepted bytearray. This caused mypy errors when passing memoryview objects from ctypes buffers. - Add Buffer type alias (Union[bytearray, memoryview]) to setters and getters - Update all function signatures to accept Buffer - Fix .decode() calls in getters to use bytes() for memoryview compat - Add 17 memoryview compatibility tests Credit: LuTiFlekSSer for identifying the memoryview compatibility issue. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…rs (#644) Adds 32 new tests exercising server-side protocol handlers through real client-server communication: block list/info/upload/download, SZL reads, clock get/set, PLC control (stop/start/compress), and error scenarios for unregistered areas and nonexistent blocks. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Tests parse_address() for all address types (V, VW, VD, V.bit) and invalid inputs, plus integration tests for Logo read/write against the built-in server covering byte, word, dword, and bit operations including boundary values and read-modify-write bit logic. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add tests to improve coverage from 78% to ~85% Add test suites for untested code paths that don't require a real PLC: - error.py: error routing, check_error(), error_wrap() decorator - connection.py: socket mocking, COTP parsing, exception paths - server/__main__.py: CLI entrypoint test - s7protocol.py: response parser tests with crafted PDUs - util/db.py: DB/Row type conversions, dict-like interface Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix test_server_cli.py when click is not installed Use pytest.importorskip to gracefully skip CLI tests when click (an optional dependency) is not available in the test environment. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Revert "Revert async client commits from master" This reverts commit 746a9b2. * Fix pre-commit issues: unused imports, hex casing, mypy types Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: add pytest-asyncio dep, ruff formatting, async docs - Add pytest-asyncio to test dependencies in pyproject.toml - Apply ruff format to async_client.py (struct.pack arg formatting) - Add AsyncClient documentation (doc/API/async_client.rst) - Add async_client to Sphinx toctree - Add async example to README.rst Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix AsyncClient.get_connected to also check connection.connected Address PR review comment: verify the underlying Connection object reports as connected, not just the client-level flag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add S7CommPlus protocol scaffolding for S7-1200/1500 support Adds the snap7.s7commplus package as a foundation for future S7CommPlus protocol support, targeting all S7-1200/1500 PLCs (V1/V2/V3/TLS). Includes: - Protocol constants (opcodes, function codes, data types, element IDs) - VLQ encoding/decoding (Variable-Length Quantity, the S7CommPlus wire format) - Codec for frame headers, request/response headers, and typed values - Connection skeleton with multi-version support (V1/V2/V3/TLS) - Client stub with symbolic variable access API - 86 passing tests for VLQ and codec modules The wire protocol (VLQ, data types, object model) is the same across all protocol versions -- only the session authentication layer differs. The protocol version is auto-detected from the PLC's CreateObject response. Reference: thomas-v2/S7CommPlusDriver (C#, LGPL-3.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus server emulator, async client, and integration tests Server emulator (snap7/s7commplus/server.py): - Full PLC memory model with thread-safe data blocks - Named variable registration with type metadata - Handles CreateObject/DeleteObject session management - Handles Explore (browse registered DBs and variables) - Handles GetMultiVariables/SetMultiVariables (read/write) - Multi-client support (threaded) - CPU state management Async client (snap7/s7commplus/async_client.py): - asyncio-based S7CommPlus client with Lock for concurrent safety - Same API as sync client: db_read, db_write, db_read_multi, explore - Native COTP/TPKT transport using asyncio streams Updated sync client and connection to be functional for V1: - CreateObject/DeleteObject session lifecycle - Send/receive with S7CommPlus framing over COTP/TPKT - db_read, db_write, db_read_multi operations Integration tests (25 new tests): - Server unit tests (data blocks, variables, CPU state) - Sync client <-> server: connect, read, write, multi-read, explore - Async client <-> server: connect, read, write, concurrent reads - Data persistence across client sessions - Multiple concurrent clients with unique sessions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Clean up security-focused wording in S7CommPlus docstrings Reframe protocol version descriptions around interoperability rather than security vulnerabilities. Remove CVE references and replace implementation-specific language with neutral terminology. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: remove pytest-asyncio dependency, fix formatting Rewrite async tests to use asyncio.run() instead of @pytest.mark.asyncio since pytest-asyncio is not a project dependency. Also apply ruff formatting fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add pytest-asyncio dependency and use native async tests Add pytest-asyncio to test dependencies and set asyncio_mode=auto. Restore async test methods with @pytest.mark.asyncio instead of asyncio.run() wrappers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI and add S7CommPlus end-to-end tests Fix ruff formatting violations and mypy type errors in S7CommPlus code that caused pre-commit CI to fail. Add end-to-end test suite for validating S7CommPlus against a real S7-1200/1500 PLC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Enhance S7CommPlus connection with variable-length TSAP support and async client improvements Support bytes-type remote TSAP (e.g. "SIMATIC-ROOT-HMI") in ISOTCPConnection, extend S7CommPlus protocol handling, and improve async client and server emulator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add extensive debug logging to S7CommPlus protocol stack for real PLC diagnostics Adds hex dumps and detailed parsing at every protocol layer (ISO-TCP, S7CommPlus connection, client) plus 6 new diagnostic e2e tests that probe different payload formats and function codes against real hardware. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus wire format for real PLC compatibility Rewrite client payload encoding/decoding to use the correct S7CommPlus protocol format with ItemAddress structures (SymbolCrc, AccessArea, AccessSubArea, LIDs), ObjectQualifier, and proper PValue response parsing. Previously the client used a simplified custom format that only worked with the emulated server, causing ERROR2 responses from real S7-1200/1500 PLCs. - client.py: Correct GetMultiVariables/SetMultiVariables request format - async_client.py: Reuse corrected payload builders from client.py - codec.py: Add ItemAddress, ObjectQualifier, PValue encode/decode - protocol.py: Add Ids constants (DB_ACCESS_AREA_BASE, etc.) - server.py: Update to parse/generate the corrected wire format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus LID byte offsets to use 1-based addressing S7CommPlus protocol uses 1-based LID byte offsets, but the client was sending 0-based offsets. This caused real PLCs to reject all db_read and db_write requests. Also fixes lint issues in e2e test file. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus session setup and legacy S7 fallback for data operations Implement the missing SetMultiVariables session handshake step that echoes ServerSessionVersion (attr 306) back to the PLC after CreateObject. Without this, PLCs reject data operations with ERROR2 (0x05A9). For PLCs that don't provide ServerSessionVersion or don't support S7CommPlus data operations, the client transparently falls back to the legacy S7 protocol. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Potential fix for code scanning alert no. 9: Binding a socket to all network interfaces Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Add CLI tools for direct PLC interaction (read, write, dump, info) Expand the snap7 CLI beyond snap7-server with subcommands for reading, writing, dumping, and inspecting PLCs directly from the terminal. Closes #621 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: skip CLI tests when click is not installed Uses pytest.importorskip("click") so test collection doesn't fail in CI environments that only install the test dependencies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Rename CLI entry point from snap7 to s7, add discover hook Renames the CLI command from `snap7` to `s7` for a cleaner interface. Adds a hook to auto-register `s7 discover` when the discovery module is available, so both PRs compose cleanly when merged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds db_read_*/db_write_* convenience methods for bool, byte, int, uint, word, dint, udint, dword, real, lreal, string, and wstring types. Closes #617 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds 70 tests validating TPKT, COTP, and S7 protocol encoding against the specification at byte level. Closes #620 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add examples cookbook and troubleshooting documentation Based on analysis of 312 issues and discussions, the two biggest sources of user confusion are S7-1200/1500 configuration and data type handling. These new pages address the most common questions. examples.rst: rack/slot reference table, PLC address mapping guide, complete data types cookbook (BOOL through DATE_AND_TIME), memory areas, analog I/O, multi-variable read, and server setup for testing. troubleshooting.rst: error message reference table, S7-1200/1500 TIA Portal configuration steps, connection recovery patterns, timeout configuration, thread safety, and protocol limitations FAQ. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add PLC support matrix documentation Add a new page documenting which Siemens PLC families are supported, their protocol capabilities, PUT/GET configuration requirements, and alternatives for unsupported PLCs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Cleanup: consolidate tests, fix docs, remove README async section README: - Remove async support section (unnecessary on landing page) Documentation: - Add S7CommPlus API docs with experimental warning - Add experimental warning to AsyncClient docs - Update PLC support matrix for S7CommPlus V1/V2 status Test consolidation (no test logic changed): - Merge test_server_coverage.py into test_server.py - Merge test_partner_coverage.py into test_partner.py - Merge test_logo_coverage.py into test_logo_client.py - Merge test_db_coverage.py into test_util.py - Rename test_s7protocol_coverage.py to test_s7protocol.py Mypy fixes: - Widen Row.set_value type to accept date/datetime/timedelta - Add type annotations in test_s7protocol.py, test_partner.py, test_connection.py, test_async_client.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix ruff formatting in test_util.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Improve S7CommPlus test coverage and fix Codecov upload Add 154 new unit tests covering codec decoders, PValue parsing for all data types, payload builders/parsers, connection response parsing, and client error paths. S7CommPlus coverage rises from 77% to 87%, with codec.py reaching 100%. Also add CODECOV_TOKEN to the workflow to fix silent upload failures on protected branches. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Cleanup: consolidate tests, fix docs, remove README async section README: - Remove async support section (unnecessary on landing page) Documentation: - Add S7CommPlus API docs with experimental warning - Add experimental warning to AsyncClient docs - Update PLC support matrix for S7CommPlus V1/V2 status Test consolidation (no test logic changed): - Merge test_server_coverage.py into test_server.py - Merge test_partner_coverage.py into test_partner.py - Merge test_logo_coverage.py into test_logo_client.py - Merge test_db_coverage.py into test_util.py - Rename test_s7protocol_coverage.py to test_s7protocol.py Mypy fixes: - Widen Row.set_value type to accept date/datetime/timedelta - Add type annotations in test_s7protocol.py, test_partner.py, test_connection.py, test_async_client.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix ruff formatting in test_util.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Improve S7CommPlus test coverage and fix Codecov upload Add 154 new unit tests covering codec decoders, PValue parsing for all data types, payload builders/parsers, connection response parsing, and client error paths. S7CommPlus coverage rises from 77% to 87%, with codec.py reaching 100%. Also add CODECOV_TOKEN to the workflow to fix silent upload failures on protected branches. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Restructure docs into logical sections Split the monolithic examples.rst and troubleshooting.rst into focused, topic-based pages and group them under clear sections in the toctree: Getting Started, User Guide, Troubleshooting, Development, API Reference. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Bumps the all-dependencies group with 5 updates: | Package | From | To | | --- | --- | --- | | [pytest-cov](https://github.com/pytest-dev/pytest-cov) | `7.0.0` | `7.1.0` | | [ruff](https://github.com/astral-sh/ruff) | `0.15.4` | `0.15.7` | | [tox](https://github.com/tox-dev/tox) | `4.46.3` | `4.50.3` | | [tox-uv](https://github.com/tox-dev/tox-uv) | `1.33.0` | `1.33.4` | | [uv](https://github.com/astral-sh/uv) | `0.10.6` | `0.10.12` | Updates `pytest-cov` from 7.0.0 to 7.1.0 - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](pytest-dev/pytest-cov@v7.0.0...v7.1.0) Updates `ruff` from 0.15.4 to 0.15.7 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.4...0.15.7) Updates `tox` from 4.46.3 to 4.50.3 - [Release notes](https://github.com/tox-dev/tox/releases) - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - [Commits](tox-dev/tox@4.46.3...4.50.3) Updates `tox-uv` from 1.33.0 to 1.33.4 - [Release notes](https://github.com/tox-dev/tox-uv/releases) - [Commits](tox-dev/tox-uv@1.33.0...1.33.4) Updates `uv` from 0.10.6 to 0.10.12 - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](astral-sh/uv@0.10.6...0.10.12) --- updated-dependencies: - dependency-name: pytest-cov dependency-version: 7.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-dependencies - dependency-name: ruff dependency-version: 0.15.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies - dependency-name: tox dependency-version: 4.50.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-dependencies - dependency-name: tox-uv dependency-version: 1.33.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies - dependency-name: uv dependency-version: 0.10.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add property-based tests with Hypothesis, fix bugs found Add 48 property-based tests using Hypothesis covering: - Roundtrip tests for all getter/setter pairs (integers, floats, strings, dates) - Roundtrip tests for S7 data type encode/decode - TPKT/COTP frame structure validation - S7 PDU structure validation - Fuzz tests for robustness against malformed input Bugs found and fixed: - set_date: used signed int16 (>h) for days offset, overflows for dates after ~2079. Fixed to unsigned int16 (>H). - set_tod: used float arithmetic (total_seconds() * 1000) causing precision loss. Fixed to use integer arithmetic on timedelta components. Known issue documented (not fixed): - wstring get/set uses character count but UTF-16-BE surrogate pairs for supplementary characters (codepoint > 0xFFFF) need 4 bytes per character. Closes #629 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Reject supplementary Unicode characters in set_wstring PLCs only support BMP characters (U+0000–U+FFFF) in WSTRING. Characters above U+FFFF require UTF-16 surrogate pairs (4 bytes) but the WSTRING length field counts 2-byte code units, causing data corruption. Validate input and raise ValueError for non-BMP characters, matching the reference PLC implementation behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix get_dtl to read full 4-byte nanosecond field and clean up fuzz test get_dtl was reading only byte 8 as a raw integer for microseconds, but the DTL format stores nanoseconds as a 4-byte big-endian uint32 in bytes 8-11. This fix reads the full field and converts ns to us. Also removes unnecessary KeyError catch from PDU fuzz test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Remove codecov.yml configuration - Remove coverage upload step from CI workflow - Remove Codecov badge from README - Keep local coverage reporting (--cov-report=term) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add get_ulint and get_lint to snap7.util exports These functions existed in snap7.util.getters but were not re-exported from snap7.util, making them harder to discover and use. Closes #651 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Export missing getters and remove unimplemented get_array stub - Add get_ulint, get_lint, and get_date_time_object to snap7.util exports - Remove get_array stub (unimplemented since 2024, raises NotImplementedError) - Clean up unused NoReturn import Closes #651 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix docstring indentation in get_lint and get_ulint The example return values had extra indentation that caused Sphinx to fail with "Unexpected indentation" errors when building docs with -W. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add S7CommPlus protocol scaffolding for S7-1200/1500 support Adds the snap7.s7commplus package as a foundation for future S7CommPlus protocol support, targeting all S7-1200/1500 PLCs (V1/V2/V3/TLS). Includes: - Protocol constants (opcodes, function codes, data types, element IDs) - VLQ encoding/decoding (Variable-Length Quantity, the S7CommPlus wire format) - Codec for frame headers, request/response headers, and typed values - Connection skeleton with multi-version support (V1/V2/V3/TLS) - Client stub with symbolic variable access API - 86 passing tests for VLQ and codec modules The wire protocol (VLQ, data types, object model) is the same across all protocol versions -- only the session authentication layer differs. The protocol version is auto-detected from the PLC's CreateObject response. Reference: thomas-v2/S7CommPlusDriver (C#, LGPL-3.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus server emulator, async client, and integration tests Server emulator (snap7/s7commplus/server.py): - Full PLC memory model with thread-safe data blocks - Named variable registration with type metadata - Handles CreateObject/DeleteObject session management - Handles Explore (browse registered DBs and variables) - Handles GetMultiVariables/SetMultiVariables (read/write) - Multi-client support (threaded) - CPU state management Async client (snap7/s7commplus/async_client.py): - asyncio-based S7CommPlus client with Lock for concurrent safety - Same API as sync client: db_read, db_write, db_read_multi, explore - Native COTP/TPKT transport using asyncio streams Updated sync client and connection to be functional for V1: - CreateObject/DeleteObject session lifecycle - Send/receive with S7CommPlus framing over COTP/TPKT - db_read, db_write, db_read_multi operations Integration tests (25 new tests): - Server unit tests (data blocks, variables, CPU state) - Sync client <-> server: connect, read, write, multi-read, explore - Async client <-> server: connect, read, write, concurrent reads - Data persistence across client sessions - Multiple concurrent clients with unique sessions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Clean up security-focused wording in S7CommPlus docstrings Reframe protocol version descriptions around interoperability rather than security vulnerabilities. Remove CVE references and replace implementation-specific language with neutral terminology. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: remove pytest-asyncio dependency, fix formatting Rewrite async tests to use asyncio.run() instead of @pytest.mark.asyncio since pytest-asyncio is not a project dependency. Also apply ruff formatting fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add pytest-asyncio dependency and use native async tests Add pytest-asyncio to test dependencies and set asyncio_mode=auto. Restore async test methods with @pytest.mark.asyncio instead of asyncio.run() wrappers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI and add S7CommPlus end-to-end tests Fix ruff formatting violations and mypy type errors in S7CommPlus code that caused pre-commit CI to fail. Add end-to-end test suite for validating S7CommPlus against a real S7-1200/1500 PLC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Enhance S7CommPlus connection with variable-length TSAP support and async client improvements Support bytes-type remote TSAP (e.g. "SIMATIC-ROOT-HMI") in ISOTCPConnection, extend S7CommPlus protocol handling, and improve async client and server emulator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add extensive debug logging to S7CommPlus protocol stack for real PLC diagnostics Adds hex dumps and detailed parsing at every protocol layer (ISO-TCP, S7CommPlus connection, client) plus 6 new diagnostic e2e tests that probe different payload formats and function codes against real hardware. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus wire format for real PLC compatibility Rewrite client payload encoding/decoding to use the correct S7CommPlus protocol format with ItemAddress structures (SymbolCrc, AccessArea, AccessSubArea, LIDs), ObjectQualifier, and proper PValue response parsing. Previously the client used a simplified custom format that only worked with the emulated server, causing ERROR2 responses from real S7-1200/1500 PLCs. - client.py: Correct GetMultiVariables/SetMultiVariables request format - async_client.py: Reuse corrected payload builders from client.py - codec.py: Add ItemAddress, ObjectQualifier, PValue encode/decode - protocol.py: Add Ids constants (DB_ACCESS_AREA_BASE, etc.) - server.py: Update to parse/generate the corrected wire format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus LID byte offsets to use 1-based addressing S7CommPlus protocol uses 1-based LID byte offsets, but the client was sending 0-based offsets. This caused real PLCs to reject all db_read and db_write requests. Also fixes lint issues in e2e test file. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus session setup and legacy S7 fallback for data operations Implement the missing SetMultiVariables session handshake step that echoes ServerSessionVersion (attr 306) back to the PLC after CreateObject. Without this, PLCs reject data operations with ERROR2 (0x05A9). For PLCs that don't provide ServerSessionVersion or don't support S7CommPlus data operations, the client transparently falls back to the legacy S7 protocol. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Potential fix for code scanning alert no. 9: Binding a socket to all network interfaces Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * Add S7CommPlus protocol scaffolding for S7-1200/1500 support Adds the snap7.s7commplus package as a foundation for future S7CommPlus protocol support, targeting all S7-1200/1500 PLCs (V1/V2/V3/TLS). Includes: - Protocol constants (opcodes, function codes, data types, element IDs) - VLQ encoding/decoding (Variable-Length Quantity, the S7CommPlus wire format) - Codec for frame headers, request/response headers, and typed values - Connection skeleton with multi-version support (V1/V2/V3/TLS) - Client stub with symbolic variable access API - 86 passing tests for VLQ and codec modules The wire protocol (VLQ, data types, object model) is the same across all protocol versions -- only the session authentication layer differs. The protocol version is auto-detected from the PLC's CreateObject response. Reference: thomas-v2/S7CommPlusDriver (C#, LGPL-3.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus server emulator, async client, and integration tests Server emulator (snap7/s7commplus/server.py): - Full PLC memory model with thread-safe data blocks - Named variable registration with type metadata - Handles CreateObject/DeleteObject session management - Handles Explore (browse registered DBs and variables) - Handles GetMultiVariables/SetMultiVariables (read/write) - Multi-client support (threaded) - CPU state management Async client (snap7/s7commplus/async_client.py): - asyncio-based S7CommPlus client with Lock for concurrent safety - Same API as sync client: db_read, db_write, db_read_multi, explore - Native COTP/TPKT transport using asyncio streams Updated sync client and connection to be functional for V1: - CreateObject/DeleteObject session lifecycle - Send/receive with S7CommPlus framing over COTP/TPKT - db_read, db_write, db_read_multi operations Integration tests (25 new tests): - Server unit tests (data blocks, variables, CPU state) - Sync client <-> server: connect, read, write, multi-read, explore - Async client <-> server: connect, read, write, concurrent reads - Data persistence across client sessions - Multiple concurrent clients with unique sessions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Clean up security-focused wording in S7CommPlus docstrings Reframe protocol version descriptions around interoperability rather than security vulnerabilities. Remove CVE references and replace implementation-specific language with neutral terminology. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: remove pytest-asyncio dependency, fix formatting Rewrite async tests to use asyncio.run() instead of @pytest.mark.asyncio since pytest-asyncio is not a project dependency. Also apply ruff formatting fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add pytest-asyncio dependency and use native async tests Add pytest-asyncio to test dependencies and set asyncio_mode=auto. Restore async test methods with @pytest.mark.asyncio instead of asyncio.run() wrappers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI and add S7CommPlus end-to-end tests Fix ruff formatting violations and mypy type errors in S7CommPlus code that caused pre-commit CI to fail. Add end-to-end test suite for validating S7CommPlus against a real S7-1200/1500 PLC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Enhance S7CommPlus connection with variable-length TSAP support and async client improvements Support bytes-type remote TSAP (e.g. "SIMATIC-ROOT-HMI") in ISOTCPConnection, extend S7CommPlus protocol handling, and improve async client and server emulator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add extensive debug logging to S7CommPlus protocol stack for real PLC diagnostics Adds hex dumps and detailed parsing at every protocol layer (ISO-TCP, S7CommPlus connection, client) plus 6 new diagnostic e2e tests that probe different payload formats and function codes against real hardware. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus wire format for real PLC compatibility Rewrite client payload encoding/decoding to use the correct S7CommPlus protocol format with ItemAddress structures (SymbolCrc, AccessArea, AccessSubArea, LIDs), ObjectQualifier, and proper PValue response parsing. Previously the client used a simplified custom format that only worked with the emulated server, causing ERROR2 responses from real S7-1200/1500 PLCs. - client.py: Correct GetMultiVariables/SetMultiVariables request format - async_client.py: Reuse corrected payload builders from client.py - codec.py: Add ItemAddress, ObjectQualifier, PValue encode/decode - protocol.py: Add Ids constants (DB_ACCESS_AREA_BASE, etc.) - server.py: Update to parse/generate the corrected wire format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus LID byte offsets to use 1-based addressing S7CommPlus protocol uses 1-based LID byte offsets, but the client was sending 0-based offsets. This caused real PLCs to reject all db_read and db_write requests. Also fixes lint issues in e2e test file. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus session setup and legacy S7 fallback for data operations Implement the missing SetMultiVariables session handshake step that echoes ServerSessionVersion (attr 306) back to the PLC after CreateObject. Without this, PLCs reject data operations with ERROR2 (0x05A9). For PLCs that don't provide ServerSessionVersion or don't support S7CommPlus data operations, the client transparently falls back to the legacy S7 protocol. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus V2 protocol support (TLS + IntegrityId) Implements V2 protocol support for S7-1200/1500 PLCs with modern firmware: - TLS 1.3 activation between InitSSL and CreateObject - OMS exporter secret extraction for legitimation key derivation - Dual IntegrityId counters (read vs write) in V2 PDU headers - Password legitimation module (legacy SHA-1 XOR + new AES-256-CBC) - V2 server emulator with TLS and IntegrityId tracking - 39 new tests covering all V2 components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Complete V2 legitimation with cryptography optional dependency - Add cryptography as optional dep: pip install python-snap7[s7commplus] - Implement connection.authenticate() with challenge/response flow - Wire up legitimation in client.connect(password=...) - Auto-detect legacy (SHA-1 XOR) vs new (AES-256-CBC) auth mode - Add legitimation protocol methods: get challenge, send response - 46 tests now (was 39), including AES roundtrip verification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: skip V2 crypto tests when cryptography not installed - Skip TestBuildNewResponse when cryptography package is unavailable (CI only installs [test] extras, not [s7commplus]) - Fix extra blank line in protocol.py that failed ruff format check Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Install s7commplus extras in CI to test cryptography-dependent code Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Add PROFINET DCP network discovery Wraps pnio-dcp library for discovering Siemens PLCs on the local network. Includes Device dataclass, discover() and identify() functions, and CLI entry point. Closes #622 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Export discover_command for s7 CLI integration Exports a reusable click command (discover_command) that the s7 CLI can auto-register as `s7 discover`. Removes the standalone snap7-scan entry point in favor of the unified s7 CLI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- source-build.yml: uv venv + uv pip install build + python -m build → uv build - publish-pypi.yml: pip install build + python -m build → uv build - publish-test-pypi.yml: same - test.yml: uv venv + uv pip install → uv sync --extra - doc.yml: uv venv + uv pip install → uv sync --extra uv venvs don't include pip, so workflows using bare pip or python -m build (which needs pip internally) break. Use uv build for building and uv sync for dependency installation. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add auto-reconnect/heartbeat section to connection-issues.rst - Update limitations.rst: discovery is available via PROFINET DCP, S7CommPlus V1/V2 are now supported - Update plc-support.rst: V2 is functional (not "in development"), fix V2 encryption to TLS 1.3, update protocol overview - Add V2 TLS connection and password authentication docs to API/s7commplus.rst - Add LINT/ULINT data type sections to reading-writing.rst Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add tests for CLI discover, legitimation failures, async client, and heartbeat New test file covering identified coverage gaps: - CLI discover command: help, devices found/not found, timeout, import error - Legitimation failure paths: not connected, no TLS, no OMS secret, edge cases - S7CommPlus async client: connect, read, write, context manager, properties - Heartbeat concurrency: rapid reads and writes during active heartbeat Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove unused threading import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add TLS support to S7CommPlus async client Implement TLS 1.3 for S7CommPlusAsyncClient, bringing feature parity with the sync S7CommPlusConnection for V2 protocol connections: - Add use_tls, tls_cert, tls_key, tls_ca parameters to connect() - Implement _activate_tls() using asyncio start_tls() for in-place transport upgrade - Add authenticate() method with full legitimation support (legacy SHA-1 XOR and new AES-256-CBC modes) - Add V2 post-connection checks (require TLS, enable IntegrityId) - Reset TLS state on disconnect - Fix TLS 1.3 cipher configuration for Python 3.13+ compatibility (use set_ciphersuites instead of set_ciphers for TLS 1.3) The cipher fix also applies to the sync connection.py to prevent the same issue on Python 3.14+. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix ruff formatting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Instead of probing data operations and falling back on ERROR2, properly complete the V1 session setup by parsing ServerSessionVersion (attribute 306) from the CreateObject response and echoing it back via SetMultiVariables. This should fix the ERROR2 (0x05A9) rejections from real S7-1200/1500 PLCs with firmware v4.0+. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ion (#661) Instead of probing data operations and falling back on ERROR2, properly complete the V1 session setup by parsing ServerSessionVersion (attribute 306) from the CreateObject response and echoing it back via SetMultiVariables. This should fix the ERROR2 (0x05A9) rejections from real S7-1200/1500 PLCs with firmware v4.0+. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Bumps [requests](https://github.com/psf/requests) from 2.32.5 to 2.33.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](psf/requests@v2.32.5...v2.33.0) --- updated-dependencies: - dependency-name: requests dependency-version: 2.33.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Collapse 3 layers (snap7, snap7.s7commplus, s7) into 2: - snap7/ stays untouched as legacy S7 protocol - s7/ is the new unified frontend with S7CommPlus + legacy fallback Key changes: - Move all S7CommPlus protocol code from snap7/s7commplus/ to s7/ - Remove duplicated fallback logic — now lives only in s7.Client - Pure S7CommPlus clients (_s7commplus_client.py) have no fallback - s7.Client tries S7CommPlus first, falls back to snap7.Client - Rename tests: test_s7commplus_* → test_s7_* - Update all imports, docs, tooling (mypy, ruff, tox) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflicts in s7/_s7commplus_client.py and s7/_s7commplus_async_client.py — keep our refactored versions which already include the session setup fix from #661 but without the fallback logic (now owned by s7.Client). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- s7.Client.db_write() and s7.AsyncClient.db_write() now return int (0) matching snap7.Client behavior - s7.AsyncClient.disconnect() now returns int (0) matching snap7.AsyncClient - doc/introduction.rst: explain two-package architecture (snap7 vs s7) - doc/connecting.rst: add tip about s7 package for S7-1200/1500 - Keep S7CommPlus marked as experimental throughout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.5 to 46.0.6. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](pyca/cryptography@46.0.5...46.0.6) --- updated-dependencies: - dependency-name: cryptography dependency-version: 46.0.6 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the all-actions group with 1 update: [actions/deploy-pages](https://github.com/actions/deploy-pages). Updates `actions/deploy-pages` from 4 to 5 - [Release notes](https://github.com/actions/deploy-pages/releases) - [Commits](actions/deploy-pages@v4...v5) --- updated-dependencies: - dependency-name: actions/deploy-pages dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-actions ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the all-dependencies group with 5 updates: | Package | From | To | | --- | --- | --- | | [hypothesis](https://github.com/HypothesisWorks/hypothesis) | `6.151.9` | `6.151.10` | | [ruff](https://github.com/astral-sh/ruff) | `0.15.7` | `0.15.8` | | [tox](https://github.com/tox-dev/tox) | `4.50.3` | `4.51.0` | | [uv](https://github.com/astral-sh/uv) | `0.10.12` | `0.11.2` | | [cryptography](https://github.com/pyca/cryptography) | `46.0.5` | `46.0.6` | Updates `hypothesis` from 6.151.9 to 6.151.10 - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](HypothesisWorks/hypothesis@hypothesis-python-6.151.9...hypothesis-python-6.151.10) Updates `ruff` from 0.15.7 to 0.15.8 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.7...0.15.8) Updates `tox` from 4.50.3 to 4.51.0 - [Release notes](https://github.com/tox-dev/tox/releases) - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - [Commits](tox-dev/tox@4.50.3...4.51.0) Updates `uv` from 0.10.12 to 0.11.2 - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](astral-sh/uv@0.10.12...0.11.2) Updates `cryptography` from 46.0.5 to 46.0.6 - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](pyca/cryptography@46.0.5...46.0.6) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.151.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies - dependency-name: ruff dependency-version: 0.15.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies - dependency-name: tox dependency-version: 4.51.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-dependencies - dependency-name: uv dependency-version: 0.11.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-dependencies - dependency-name: cryptography dependency-version: 46.0.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [pygments](https://github.com/pygments/pygments) from 2.19.2 to 2.20.0. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](pygments/pygments@2.19.2...2.20.0) --- updated-dependencies: - dependency-name: pygments dependency-version: 2.20.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Reorganize README: introduction first, then installation, then release notes for 3.0 and the upcoming 3.1 (S7CommPlus support). Add call for testing with a list of PLCs that need verification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move S7CommPlus into s7/ package, simplify to 2-layer architecture
….0.6 chore(deps): bump cryptography from 46.0.5 to 46.0.6
…-actions-d47ceab2ed chore(deps): bump actions/deploy-pages from 4 to 5 in the all-actions group
…s-61cade4300 chore(deps): bump the all-dependencies group with 5 updates
chore(deps): bump pygments from 2.19.2 to 2.20.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi! This is not a code PR — just a heads-up since your repo has issues disabled.
We noticed your multi-variable read optimizer (sort-merge-packetize pipeline) and were impressed by the approach. We've implemented a similar optimization in upstream python-snap7, inspired by your work:
Our PR: gijzelaerr#641
Our implementation follows the same core idea (sort → merge → packetize → extract), with some differences:
MaxConnectionsdescribes TCP slots, not in-flight PDU tolerancemax_gapviaclient.multi_read_max_gap_OptimizationPlan) instead of fields on ClientIf you're interested, we'd welcome your review or any contributions back to upstream. If there are features from your fork we missed, feel free to open issues or PRs on gijzelaerr/python-snap7.
Thanks for the inspiration!