# pyserial: three Python 2 packaging scripts in a project that now requires 3.10

> The serial port library almost every Python hardware tutorial imports, distributed under one name and imported under another, with a coverage gate set at twenty percent and a release list that mixes a 2025 tag with two 2020 tags published half a minute apart.

**pyserial/pyserial** — Python serial port access library

- Repository: https://github.com/pyserial/pyserial
- Website: http://pyserial.readthedocs.io/en/latest/
- Stars: 3,576 · Forks: 1,164
- Language: Python
- License: NOASSERTION
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/pyserial-pyserial

## The packaging examples are named for a Python that the project no longer supports

The examples directory contains three scripts whose names declare the runtime they were written for:

The names are setup-miniterm-py2exe.py, setup-rfc2217_server-py2exe.py and setup-wxTerminal-py2exe.py, all sitting directly in the examples directory.

Those names end in the suffix for a Python 2 packaging tool that builds a single-file executable. Meanwhile the build configuration requires Python 3.10 or newer and lists classifiers for five versions from 3.10 through 3.14, and the release is a 3.x. So the repository ships build recipes for a language generation it can no longer run, and nothing in the build configuration excludes them. They are not referenced by the packaging metadata, so they are not installed and they are not run by the test suite, which means nothing has broken and nothing will notice if they rot further. They are a fossil of the project's own history, visible only to somebody reading the tree.

## The coverage gate is twenty percent and the path map names a directory that is not there

The coverage configuration is the most surprising block in the build file:

```
[tool.coverage.run]
relative_files = true
parallel = true
branch = true
source = [
    "serial",
    "test",
]

[tool.coverage.report]
skip_covered = true
fail_under = 20
```

Branch coverage on, and a floor of twenty percent, meaning four fifths of the library is allowed to be unexercised. For a library whose backends each talk to a different operating system's serial subsystem, that is an honest floor rather than a broken one: a green suite here does not mean the code works, it means the parts that can run without hardware do. The second half is a leftover. The path mapping tells coverage to look for sources under a directory named for a source layout this repository does not use, when the package sits in a directory named for the package itself. Copyed from a template and never updated.

## The release list puts a 2025 tag above two 2020 tags published 33 seconds apart

Three releases are listed. The newest is 3.5, published 2025-11-20. Below it is a 3.5 beta, and below that is 3.4, and both of those carry 2020 timestamps, the beta at 01:18:09 and the final at 01:18:42 on the same day. So a beta of 3.5 appears above a final release of the earlier line, and the two of them were published thirty-three seconds apart, which is the signature of two existing tags being re-uploaded rather than two releases being cut. Two of the three entries also have an empty release name where the newest has a matching one. The practical effect is that sorting releases by date does not give you a version history, and anyone looking for what changed in 3.5 has to read the changelog file in the repository instead.

## The two console commands are named only in the metadata

The packaging metadata installs two programs:

```
[project.scripts]
pyserial-miniterm = "serial.tools.miniterm:main"
pyserial-ports = "serial.tools.list_ports:main"
```

A terminal emulator for serial ports and a port enumeration utility, installed into your environment's script directory the moment you install the library. Neither appears anywhere in the readme, which is a hundred and seventy-five words long and contains no API documentation, no examples and no mention of either command. It points at a documentation directory and an external site instead. So the most immediately useful thing about this package for somebody who has just wired a board to a USB adapter is discoverable only by reading the build file, which is the opposite of where anybody looks.

## The readme is reStructuredText and predates the current release line

The front page is written in reStructuredText, complete with an overline title, a substitution for a badge, explicit link targets and image options with alignment attributes. The title block is three lines of markup with the package name and a badge reference embedded in it. The content is an overview that says the module encapsulates serial port access, provides backends for Windows, macOS, Linux and BSD, possibly any POSIX compliant system, and that the module named serial automatically selects the appropriate one. Then two install commands, one for the package index and one for conda, a line about Windows installers being available, and a link to a file in the documentation directory for everything else. The copyright line reads 2001 to 2020, so the page has not been meaningfully rewritten in six years while the library is on its third major line.

## It claims production stability and says the issues get no service level

The classifiers include a development status of five, production and stable, alongside an audience that covers both developers and end users on a desktop, which is a confident pair of claims for a twenty-five-year-old library with a 2025 release. The distribution is BSD-3-Clause in the build file and the readme says BSD in the author's name, while the repository's own recorded licence value says nothing at all, so the terms are established by reading the licence file. Against that, the issue count in the repository is in the hundreds and the project is the kind of thing where an unanswered question is usually a missing feature request rather than a bug. Neither fact contradicts the classifier. Both belong in the same paragraph, because a library's stability claim covers its code and not its inbox.

## The examples include serial-over-TCP bridges with no exposure guidance

The examples directory is not all teaching material. Alongside the terminal and its packaging scripts there is a server implementing the serial-over-TCP protocol, a script that redirects a TCP port to a serial port, a script that publishes a port, and one written against a low-level AT command protocol. Those are genuinely useful, and they are also the shape of thing people run on a machine and forget about. The readme says nothing about them beyond a pointer to the directory. So if you start one of these on a host with an address, the exposure model is whatever the protocol implementation does, and the project has not told you what that is. None of this is a criticism of the examples, which are provided as examples; it is the gap between shipping them and saying anything about them.

## Conclusion

Use it, because for reading a serial port from Python there is nothing better and the import name is unlikely to change under you. Two things to know before you rely on it. The distribution is installed as one name and imported as another, and every tutorial gets that right only by accident of history, so read it once and stop worrying. And the package declares itself production stable while carrying a coverage floor of twenty percent, which means most of its code paths have never been executed by its own test suite, and that is expected rather than alarming: a serial backend can only really be tested against real hardware on four operating systems. If your use is a microcontroller on a USB adapter, read the timeout and write behaviour from the documentation directory rather than assuming the defaults, because the readme contains no API documentation at all.

## FAQ

### What is the difference between pyserial and serial?

One is the distribution you install and the other is the module you import. The project is published as pyserial, and the readme says the module named serial automatically selects the appropriate backend for the operating system, providing backends for Windows, macOS, Linux and BSD. The install command is pip install pyserial, and your code imports serial.

### How do I install pyserial?

Three routes are documented. pip install pyserial is the one that works for most users. conda install with the conda-forge channel is also given, with builds available for Linux, macOS and Windows. And prebuilt Windows installers are linked from the download page. The project requires Python 3.10 or newer.

### Is a pyserial write blocking?

The readme does not say. It contains an overview, two install commands and a pointer to a documentation directory in the repository, with no API reference, no examples and no discussion of timeouts or write behaviour. Those details live in the documentation directory and in the online documentation the readme links.

### What commands does installing pyserial give me?

Two console programs, and neither is mentioned in the readme. One is a serial port terminal emulator and the other lists available ports. Both are declared as script entry points in the packaging metadata, so they appear on your path when the library is installed. There is also one optional dependency group, named for a specific USB serial adapter chip, which brings in a HID library.

## Sources

- [Issues](https://github.com/pyserial/pyserial/issues)
- [Project website](http://pyserial.readthedocs.io/en/latest/)
- [pyserial/pyserial on GitHub](https://github.com/pyserial/pyserial)
- [README](https://github.com/pyserial/pyserial/blob/master/README.md)
- [Releases](https://github.com/pyserial/pyserial/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pyserial-pyserial
