# coveralls: publishing coverage.py results to coveralls.io from Python

> The coveralls package takes the output of coverage.py and publishes it to coveralls.io, so a Python project can show its coverage online with a single command after a test run. The current 4.x line requires Python 3.11 or newer, depends on coverage 6.5 or later, and ships on PyPI, conda-forge and two container registries.

**TheKevJames/coveralls-python** — Show coverage stats online via coveralls.io

- Repository: https://github.com/TheKevJames/coveralls-python
- Website: https://coveralls-python.readthedocs.io
- Stars: 573 · Forks: 185
- Language: Python
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/thekevjames-coveralls-python

## Three commands and a hosted report

coveralls.io is a service for publishing your coverage stats online, and this package integrates with coverage.py, and therefore with pytest, nosetests and the rest of that family, in your Python projects.

The whole workflow is three commands:

```
    pip install coveralls
    coverage run --source=mypkg -m pytest tests/
    coveralls
```

That is the whole integration. The first line installs the package, the second runs the test suite under coverage, and the third uploads the result. There is no configuration file to write and no plugin to enable in the test runner, which is the reason to reach for this rather than a coverage plugin that has to be wired into your test setup.

The upload needs credentials, and how those are supplied is a decision the service makes rather than this package, so the package's job is to read them from the environment in the way the service expects. In continuous integration that is a secret configured on the runner; locally it is usually a token or a repository identifier set in the shell. The documentation site covers the details.

The output is a coverage report on the coveralls site, which is what gives a project the familiar badge and the history of how coverage moved over time. The readme's own badge points at the project page for this repository, which is a small demonstration of the loop closing.

The package name on the index is coveralls even though the project is called coveralls-python, and the console script is installed under two names, coveralls and python-coveralls, so a project that already has a command of that name can pick the other.

## The 4.x line dropped old Python, and the docs explain how to cope

The version compatibility section is the part of the readme that will matter to anyone with an older environment.

As of version 2.0, support for end-of-life Python versions and particularly old versions of coverage was dropped. Support for non-end-of-life environments is provided on a best-effort basis and will generally be removed once they make maintenance too difficult.

The current manifest is much stricter than that wording suggests. The project requires Python 3.11 or newer, and the coverage dependency is split by interpreter version: coverage 6.5 or later but below 8.0 on Python below 3.15, and coverage 7.0.2 or later but below 8.0 on Python 3.15 and above. The rest of the runtime dependencies are requests, typer for the command line interface, and urllib3.

The advice for people on old environments is practical rather than aspirational. If you are running on an outdated environment with a new enough package manager to support version checks, then installing the latest compatible version should do the trick automatically. If you are even more outdated than that, pin to coveralls below 2. Support for outdated environments is not guaranteed, and the readme asks that you mention your environment if you open a ticket, adding that the maintainer will consider backporting fixes to the 1.x branch if the need is great enough.

That is a reasonable position for a small package that has to work across a wide range of environments, and the version-conditional dependency is the kind of thing that avoids a resolver conflict for most people without them noticing.

The optional extras are thin. There is a yaml extra for pyyaml, and that is the only one, which tells you the YAML support is the part of the feature set that is not installed by default.

## Distributed four ways, and a container built for one purpose

The distribution channels are the second thing to know, because the answer to how do I install this is not always pip.

The package is on PyPI as coveralls, on conda-forge as coveralls, and there are container images under the thekevjames organisation on both Docker Hub and Quay. The readme carries badges for each of them, along with a download count badge for both PyPI and conda-forge.

The Dockerfile is unusual in a way that is worth reading. It uses the syntax directive for the dockerfile frontend, and its first build arguments are two Renovate datasource declarations, one pinning the coveralls version from PyPI and one pinning the git version from the alpine repository, with the second annotated as coming from the alpine 3.24 git package with loose versioning.

The base image is python:3.15-alpine3.24, and git is installed with a cache mount for the apk cache. The coveralls package itself is then installed with pip, also using a cache mount, pinned to the version from the build argument. The Renovate comments say exactly why the arguments are there: so that the dependency updates are automated.

So the image exists for a specific job, running the coveralls command inside a container rather than installing it into your own. That is the shape you want in a CI job where you would rather not have the tool on the Python environment you are testing.

The rest of the repository is a conventional Python project. There is a coveralls/ package directory, a tests/ directory, an example/ directory with a small project and a runner, a docs/ directory with Sphinx configuration, a pyproject.toml as the build definition, a uv.lock, a CHANGELOG.md, a .pre-commit-config.yaml, a .readthedocs.yml for the documentation build, and a Dockerfile.

## A small package with a long history behind it

The maintenance picture is healthy, and the version numbering tells you the story of the Python ecosystem underneath it.

The three most recent releases are 4.1.0 from 2026-02-28, 4.0.2 from 2025-11-07 and 4.0.1 from 2024-05-15. The 4.0 release line is where the project dropped the older interpreters, and 4.1.0 is a maintenance release on top of it.

The repository is not archived, the default branch is master, and the last push was on 2026-10-20, two days before the current date. The licence is MIT, with a LICENSE.rst file at the root rather than the more common LICENSE, and the project metadata declares the same licence.

The test and development tooling is thorough for a package this size. The dev group pins flake8 with several plugins that check specific rules, including one for broken lines, one for complicated walrus expressions, one for import restrictions and one for requirements, plus pylint, pytest and responses, which is the library for mocking HTTP responses in tests. There is a separate docs group with Sphinx, and the changelog is generated with git-cliff, which is configured in the pyproject with a templated body.

The project is maintained by Kevin James, whose name and contact address are in the package metadata, and it is worth noting that the repository is under TheKevJames organisation rather than the original project name, which usually indicates a handover. The CircleCI and GitHub Actions badges are both present, so the test suite runs in two places.

## Conclusion

coveralls suits a Python project that already measures coverage with coverage.py and wants a hosted badge and history with little configuration, and it suits a team moving off a hosted CI service that requires a specific plugin. It does not suit a project that wants coverage results to stay on its own infrastructure, since the service is the point, and the 4.x line has dropped every Python older than 3.11. Before adding it, check that your coverage version is inside the supported range, and if you are on an old interpreter, pin to a 2.x release, which the documentation still describes.

## FAQ

### How do I publish coverage stats from a Python project to coveralls.io?

Install the coveralls package, run the test suite under coverage with coverage run --source=mypkg -m pytest tests/, and then run the coveralls command to upload the result. The package integrates with coverage.py and therefore with pytest, nosetests and similar runners, with no plugin to configure.

### Which Python versions does the current coveralls package support?

The current manifest requires Python 3.11 or newer, with coverage 6.5 or later but below 8.0 on Python below 3.15 and coverage 7.0.2 or later on Python 3.15 and above. Support for end-of-life environments was dropped at version 2.0 and is provided on a best-effort basis.

### Where can I install the coveralls package from?

It is on PyPI as coveralls, on conda-forge as coveralls, and there are container images on Docker Hub and Quay under the thekevjames organisation. The console script is installed under both the coveralls and python-coveralls names.

### What does the coveralls Dockerfile do?

It builds on python:3.15-alpine3.24, installs a pinned git version with a cache mount, then pip installs a pinned coveralls version with another cache mount. The version arguments are Renovate datasource declarations, so dependency updates are automated.

## Sources

- [License: MIT](https://github.com/TheKevJames/coveralls-python/blob/master/LICENSE)
- [Project website](https://coveralls-python.readthedocs.io)
- [README](https://github.com/TheKevJames/coveralls-python/blob/master/README.md)
- [Releases](https://github.com/TheKevJames/coveralls-python/releases)
- [TheKevJames/coveralls-python on GitHub](https://github.com/TheKevJames/coveralls-python)

---

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