# thriftpy: a compatibility shim that points at thriftpy2

> The thriftpy package on PyPI is no longer the implementation, it is a thin wrapper that installs a pinned thriftpy2 release and re-exports it under the historical name, so existing imports keep working while development happens in the other project. This looks at that arrangement, and at what a team should actually depend on.

**Thriftpy/thriftpy** — thriftpy is now a thin shim around https://github.com/Thriftpy/thriftpy2

- Repository: https://github.com/Thriftpy/thriftpy
- Stars: 1,148 · Forks: 281
- Language: Python
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/thriftpy-thriftpy

## What you install is one package around another

The readme's opening line is the whole story. `thriftpy` is now a thin compatibility shim around thriftpy2, and installing `thriftpy` installs the matching `thriftpy2` release and re-exports it under the historical `thriftpy` package name. Existing code that uses `import thriftpy` can keep that import while running on the maintained `thriftpy2` implementation.

That is a deprecation handled as a package, which is a neat piece of engineering. The alternative, telling every downstream project to change its imports, tends to result in a long tail of codebases that never get around to it and therefore never get the bug fixes. Wrapping the old name around the new one gets the same result without asking anyone to do anything.

The consequence for a reader is that the documentation in this repository is a pointer, not a manual. For full documentation and usage details, the project tells you to use the thriftpy2 project, and everything about the API, the IDL loading, the RPC server and client live there.

The repository itself is thin accordingly. There is a `thriftpy/` package directory, an `examples/` directory with `calculator/`, `gunicorn_thrift/`, `multiplexer/`, `oneway/`, `pingpong/` and `tutorial/`, a `benchmark/` directory, a `CHANGES.rst`, a `MANIFEST.in`, a `README.rst` and a `setup.py`.

## Release access, not disagreement, caused the split

The background section explains the history in a way that is worth reading, because it removes a plausible wrong assumption.

For a while the project did not have release access for the original `thriftpy` package, so active development moved to `thriftpy2`. The readme is explicit that thriftpy2 is the direct continuation of thriftpy and that, apart from the package name, it provides the same project and implementation.

After seeing that some users still depend on the `thriftpy` name, the maintainers recovered the needed release access and turned `thriftpy` into a shim around `thriftpy2`. Going forward, the two are released in sync with the same version number, and users can choose either package name.

So the split was an administrative accident, not an argument about the design. The two projects are the same codebase with two names, one of which exists purely for compatibility. That is why the readme can be this short without being unhelpful, and it is why a comparison between the two would be a comparison of a package with itself.

The practical consequence for a team is a version policy question rather than a technical one. Because the two are released in lockstep, upgrading the shim means upgrading the wrapped implementation, and pinning the shim pins the implementation to a version you may want to move off later.

## The ping-pong example, and the API it exercises

The readme's minimal example is the canonical Thrift one, a service with a single string returning method, and it is short enough to show the whole model.

The interface definition is a Thrift file:

```
service PingPong {
    string ping(),
}
```

And the server loads that file by name, binds a dispatcher class to it, and serves:

```python
import thriftpy
from thriftpy.rpc import make_server

pingpong_thrift = thriftpy.load("pingpong.thrift", module_name="pingpong_thrift")

class Dispatcher(object):
    def ping(self):
        return "pong"

server = make_server(pingpong_thrift.PingPong, Dispatcher(), "127.0.0.1", 6000)
server.serve()
```

The client is the mirror image:

```python
import thriftpy
from thriftpy.rpc import make_client

pingpong_thrift = thriftpy.load("pingpong.thrift", module_name="pingpong_thrift")

client = make_client(pingpong_thrift.PingPong, "127.0.0.1", 6000)
print(client.ping())
```

Three things in that snippet are the API worth knowing. `thriftpy.load` parses the IDL file and returns a module, and the `module_name` argument names it so the generated classes live somewhere importable. `make_server` and `make_client` hide the transport, and the client is written as if the remote object were local, which is the whole point of a proxying RPC client.

The examples directory carries the same idea into more demanding shapes: a `gunicorn_thrift/` example for running the server under a real WSGI server, a `multiplexer/` example, a `oneway/` example, and a `tutorial/`.

## setup.py is where the shim contract is written down

The manifest of this repository is short enough to be the specification, and the first thing in it is a comment explaining the shape.

The comment says to keep it in lockstep with the pinned thriftpy2 dependency below, because thriftpy is a thin compatibility shim and every release tracks the thriftpy2 it wraps. And the dependency is pinned exactly:

```python
install_requires = [
    "thriftpy2==%s" % version,
]
```

So the version is defined once, at 0.7.1, and used both for this package and for the exact thriftpy2 release it wraps. An exact pin rather than a range is the right call for a compatibility shim, since the two are released in sync and a mismatched pair would be a support problem with no upside.

The rest of the manifest is the ordinary Python packaging surface. The package name is `thriftpy`, the description says it is a compatibility shim that exposes thriftpy2 under the historical thriftpy name, the author is Lx Yu, the licence is MIT, and `python_requires` is 3.7 or later. The classifiers describe the package as Development Status 4, Beta, targeted at developers, and covering CPython and PyPy.

Two details are quietly significant. `entry_points={}` is empty, so the shim exposes no console scripts and no plugins, it is purely an import shim. And `packages=find_packages(exclude=['benchmark', 'docs', 'tests'])` keeps the examples, the benchmarks and the tests out of the installed distribution, which is why the wheel is small and why the examples in this repository are for reading rather than for installing.

## Where the shim arrangement stops being the right answer

Three limits are clear.

The first is that new code should not be written against it. The package exists to absorb a rename for code that already exists. A team starting a new project should depend on thriftpy2 directly, get the documentation from that project, and not carry a wrapper it does not need. Using the shim for new code buys nothing and creates a dependency whose only purpose is compatibility.

The second is the version coupling. Because the shim pins an exact thriftpy2 release, a team that wants to move to a newer implementation cannot upgrade one without the other, and the shim release that carries the newer implementation has to exist first. The readme says the two are released in sync, so the practical cost is a short delay rather than a conflict, but it is a delay in a dependency you did not choose.

The third is the floor and the status. The manifest still declares Python 3.7 or later, which is a long way behind what most new deployments run, and the package is classified as beta with the Development Status 4, Beta, marker. The beta classification is inherited from the shim's own lineage, and it is a reason to look at thriftpy2's metadata rather than take this one at face value.

The alternative path is thriftpy2 itself, and the difference in approach is entirely in the packaging rather than in the protocol. The same implementation, the same IDL, the same RPC model, with the one difference that the name you depend on is the maintained one.

## Conclusion

thriftpy fits an existing codebase whose imports say `import thriftpy` and whose team does not want to touch them, because installing the shim gives them the maintained implementation with no code change. New code should depend on thriftpy2 directly, because the shim exists to absorb a rename rather than to be an API. Before you pin it, note that the shim's version is locked to the thriftpy2 release it wraps, so upgrading means upgrading both, and check the Python floor, which the setup.py still declares as 3.7 or later even though the package is classified as beta.

## FAQ

### What is thriftpy now?

A thin compatibility shim around thriftpy2. Installing thriftpy installs the matching thriftpy2 release and re-exports it under the historical thriftpy name, so existing `import thriftpy` code keeps working on the maintained implementation.

### Why did the project move to thriftpy2?

Because the maintainers did not have release access for the original thriftpy package for a while, so active development moved to thriftpy2, which is the direct continuation with the same project and implementation under a different name. Release access was later recovered and thriftpy became the shim.

### Which version of thriftpy2 does the thriftpy package install?

The exact matching release, pinned with `thriftpy2==%s` using the same version string as the thriftpy package itself, at 0.7.1 in the setup.py. The comment there says to keep the two in lockstep because every thriftpy release tracks the thriftpy2 it wraps.

### How do I make a simple Thrift call with thriftpy?

Load the IDL with `thriftpy.load("pingpong.thrift", module_name="pingpong_thrift")`, then use `thriftpy.rpc.make_server` with a dispatcher class or `thriftpy.rpc.make_client` with the loaded service class, as shown in the readme's ping-pong example.

### Where should I look for the full thriftpy documentation?

The readme directs you to the thriftpy2 project for full documentation and usage details, since the thriftpy repository is only a compatibility shim. The examples directory here, covering calculator, gunicorn, multiplexer, oneway, pingpong and a tutorial, is the other place to look.

## Sources

- [Issues](https://github.com/Thriftpy/thriftpy/issues)
- [License: MIT](https://github.com/Thriftpy/thriftpy/blob/master/LICENSE)
- [README](https://github.com/Thriftpy/thriftpy/blob/master/README.md)
- [Releases](https://github.com/Thriftpy/thriftpy/releases)
- [Thriftpy/thriftpy on GitHub](https://github.com/Thriftpy/thriftpy)

---

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