python-snap7: a pure Python client for Siemens S7 PLCs
a pure Python S7 communication library for interfacing with Siemens S7 PLCs
At a glance
- What is it?
- python-snap7 talks to Siemens S7 controllers over the classic S7 protocol with nothing but the Python standard library, so there is no native extension to build and no Snap7 binary to ship. It covers S7-300 and S7-400 directly and S7-1200 and S7-1500 only where PUT/GET has been enabled in TIA Portal, which is a security decision rather than a technical one.
- Who is it for?
- Adopt python-snap7 when you need to read or write PLC data from Python on a machine where you cannot install a native extension or run the Snap7 binary, and your controller is an S7-300, S7-400, or a 1200 or 1500 with PUT/GET turned on. Do not adopt it for symbolic access or optimised data blocks on the newer controllers.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the library is and what pure Python buys you
python-snap7 is a pure-Python library for communicating with Siemens S7 PLCs using the classic S7 protocol. It supports S7-300 and S7-400 controllers, as well as S7-1200 and S7-1500 controllers with PUT/GET access enabled, and it supports Python 3.10 and newer on Windows, Linux and macOS without native dependencies.
The last clause is the reason the project exists in this form. The established way to talk to a Siemens PLC from Python has been to bind to Snap7, a C library, through ctypes or a wrapper, which means a native extension to compile or a shared library to ship. On a locked-down Windows machine, in a container image you do not control, or on a platform where a wheel is not published, that is a packaging problem before it is a programming problem. This library removes it by implementing the protocol in Python itself.
The consequence is a difference in performance profile and a difference in deployment. You trade some throughput and some latency for a package that installs with pip and runs anywhere Python does, and the deployment story is worth having on its own: a monitoring script can be copied to a machine as a single file with a standard library and nothing else.
The quick start is short:
from s7 import Client
client = Client()
client.connect("192.168.1.10", 0, 1)
data = client.db_read(1, 0, 4)
client.disconnect()The connect call takes an address, a rack and a slot, which is how the S7 protocol addresses a controller: the rack and slot are the PLC's position on the network, and for an S7-1200 or S7-1500 the usual values are 0 and 1.
Note the import. The s7 package is the recommended one, and the snap7 package name is also available for backwards compatibility.
The PUT/GET constraint on S7-1200 and S7-1500
This is the single most important thing to understand before you choose this library, and the README puts it in its own section with the title S7-1200 and S7-1500.
On those controllers, python-snap7 only works when PUT/GET access is enabled in TIA Portal, and it cannot access optimised data blocks. PUT/GET is unauthenticated and disabled by default, so leaving it disabled is the more secure configuration.
That is an unusual statement for a library README because it is a security judgement rather than a technical fact, and the judgement goes against the library's own convenience. Enabling PUT/GET on a 1200 or 1500 removes a layer of authentication from the path that this library uses, and it does so for the entire controller rather than for one connection.
So the trade is explicit. If your controller has PUT/GET enabled, this library gives you a pure Python way in. If it does not, the answer is that it cannot help you, and the README says so rather than leaving you to discover it.
For the cases where PUT/GET is disabled, or where you need optimised data blocks or symbolic access, the README points to a different project, s7commplus, installed with pip install s7commplus. That is a separate, younger project implementing S7CommPlus, the protocol these controllers speak natively.
The README is careful about how it points there. It says to check the firmware versions validated so far before relying on it, and to see the PLC support matrix for what python-snap7 supports on each controller family. So the guidance is: if the classic protocol path is closed to you, use S7CommPlus, and check the compatibility data first because that path is younger and less proven.
The important thing for a reader planning an integration is that the choice of library is downstream of a configuration decision made in TIA Portal, not a purely technical selection.
The package layout, extras and command line tools
The project metadata shows a package that ships two import names and a set of optional extras that map to distinct use cases.
The build backend is setuptools with a wheel, and the project is named python-snap7 at version 3.2.1, requiring Python 3.10 or newer, with classifiers for 3.10 through 3.14. The package discovery includes both snap7* and s7*, which is how the two import names coexist, and the package data includes a py.typed marker for the snap7 package, so type checkers will use the annotations.
The extras are the interesting part, because they tell you what the maintainers consider separate use cases.
The test extra is the largest and includes pytest, pytest-asyncio, pytest-bdd pinned between 8.1 and 10, pytest-cov, pytest-html, hypothesis, mypy, types-setuptools, ruff, tox, tox-uv, types-click and uv. The behaviour-driven testing framework, the property-based testing library and the hypothesis dependency together suggest a test suite that exercises protocol behaviour rather than just API calls.
The discovery extra pulls in pnio-dcp, which is the discovery protocol used to find devices on the network, and the ppi extra pulls in pyserial 3.5 or newer for the PPI protocol. The demo extra brings in psutil, rich and click, the cli extra brings in rich and click, and the doc extra brings in sphinx with the read the docs theme.
Two console scripts are installed: snap7-server pointing at snap7.server:mainloop and s7 pointing at snap7.cli:main. The example directory matches the extras, with example/ppi.py for the PPI protocol, example/prometheus_metrics.py for exposing metrics, example/s7_symbols.py for symbolic access, example/read_multi.py and example/write_multi.py, plus a db_layouts.py and a layout text file describing a data block.
The Dockerfile builds from ubuntu:24.04 with a virtualenv at /venv and the package installed into it, and the Makefile is a developer file that drives uv, tox, ruff and mypy rather than an installation path.
Real PLC testing, and the acceptance procedure
The README points at a document called Real-PLC acceptance testing, described as the safe volunteer hardware-test procedure.
That is a detail that tells you a lot about how the project is run. A protocol library for PLCs can be tested against a simulator, and simulators will not catch everything: the difference between what a real controller does with a malformed frame and what a simulator assumes is exactly where the bugs live. The README therefore documents a procedure for testing against real hardware, and the pytest configuration carries markers for it, including one for end-to-end tests requiring a real PLC connection and another for a versioned real-PLC acceptance scenario, plus a smoke marker for read-only tests.
The word volunteer in the phrase safe volunteer hardware-test procedure is also telling. It suggests that the hardware is donated or borrowed, and that the tests that touch it are opt-in for people who have a controller in front of them rather than something that runs on every commit.
The pytest configuration in the pyproject file is organised around those markers, which means a contributor without a PLC can still run the rest of the suite, and a contributor with one can run the acceptance scenarios deliberately.
For a user evaluating the library, this matters. It tells you that the project is tested against real controllers rather than only against a model of them, and that the acceptance criteria for a change are written down. The support matrix page, linked from the README, and the firmware version list are the two documents to check before relying on the library against a specific controller in production.
Limits: a subset of the protocol, and a security trade the library does not make for you
The limits are visible in what the README says and in what it defers to another project.
The first is that optimised data blocks on S7-1200 and S7-1500 are out of reach. That is not a bug to be fixed in this library but a consequence of the protocol path it speaks, and the README redirects to S7CommPlus for those cases. Symbolic access is in the same category.
The second is the PUT/GET dependency and its security cost. The library does not enable PUT/GET, cannot enable it for you, and cannot be used without it on the newer controllers. If your security policy forbids turning it on, this library is not an option for that hardware and you need the younger S7CommPlus project instead.
The third is that pure Python has a performance ceiling. The protocol work is done in Python rather than in C, so per-operation latency and throughput will not match a native Snap7 binding. For reading a handful of values from a PLC every few seconds, that is irrelevant. For a tight polling loop or a high-volume data acquisition job, it is the deciding factor, and the right answer is the native library.
The fourth is the immaturity of the alternative. The README describes s7commplus as a separate, younger project, and tells you to check the firmware versions validated so far before relying on it. Moving to it is the correct move when you need symbolic access, and it carries more risk than the mature path.
The fifth is the version matrix in general. The library supports a range of controller families across many firmware versions, and the compatibility is documented in the support matrix rather than being implicit. A project that has to state which PLC firmware it supports will need to read that page rather than assume.
The last is the licensing of the data itself. The library is MIT and the licence is MIT, but a PLC vendor's licence terms govern what you may do with the data you read, and that is outside the scope of any open source wrapper.
python-snap7 against native Snap7 bindings and against an OPC UA client
Two comparisons make the choice clearer.
The first is against a native Snap7 binding, whether through ctypes or through a maintained wrapper. The difference in approach is where the work happens. The native library is C, compiled for the platform, and it is faster per operation, and it needs a shared library present at runtime and usually a matching wheel for your Python and platform. python-snap7 is Python, installs with pip with no compiler, and runs wherever Python does.
For the common case, which is a monitoring script, a data collector, or a test rig that talks to a controller from a laptop or a container, the packaging advantage is decisive. The performance difference rarely matters, because the PLC is the slow part of the conversation. The performance difference matters when you are doing something like collecting a fast analogue channel, and at that point you would use the native library anyway.
The second comparison is against an OPC UA client. This is the comparison most projects should make first, because OPC UA is the modern, vendor-neutral industrial protocol and it is what a Siemens controller from a recent firmware generation supports natively, with authentication, encryption and structured data. The difference in approach is that OPC UA is a different protocol entirely, negotiated over the network with a proper session model, whereas the classic S7 protocol that this library speaks is a comparatively simple request and response scheme with no session security.
That last point explains the PUT/GET discussion. A modern client that speaks OPC UA to a 1200 or 1500 does not need PUT/GET enabled and does not need the controller's classic protocol unlocked. So the honest ordering is: if your controller and your requirements allow OPC UA, use an OPC UA client and you avoid the security trade-off entirely. If you are working with older S7-300 and S7-400 hardware, or you have a specific reason to use the classic protocol, then python-snap7 is a clean way to do it without native dependencies.
Editorial conclusion
Adopt python-snap7 when you need to read or write PLC data from Python on a machine where you cannot install a native extension or run the Snap7 binary, and your controller is an S7-300, S7-400, or a 1200 or 1500 with PUT/GET turned on. Do not adopt it for symbolic access or optimised data blocks on the newer controllers. Verify first whether your PLC has PUT/GET enabled, since the library cannot work without it, that the firmware version you run is covered by the project support matrix.
Frequently asked questions
How do I connect to a Siemens PLC with python-snap7?
Import the Client class from the s7 package, which is the recommended import name, then create it, connect with the controller address and the rack and slot numbers, and read or write data blocks. The quick start in the README connects to 192.168.1.10 with rack 0 and slot 1 and reads four bytes from data block 1 before disconnecting.
Does python-snap7 work with S7-1200 and S7-1500 controllers?
Only when PUT/GET access has been enabled in TIA Portal, and it cannot access optimised data blocks in that case. PUT/GET is unauthenticated and disabled by default, so the README says leaving it disabled is the more secure configuration. If you need symbolic access or optimised blocks, the README points to the s7commplus package instead.
What are the requirements for installing python-snap7?
Python 3.10 or newer, on Windows, Linux or macOS, with no native dependencies. The project is on PyPI as python-snap7, installs with pip install python-snap7, and is MIT licensed. Optional extras cover testing, a CLI, a demo, documentation, network discovery through pnio-dcp and the older PPI protocol through pyserial.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gijzelaerr-python-snap7)