How to generate Python from Thrift.
When your Python code imports Thrift generated files, Pants will detect the imports and run the Apache Thrift compiler to generate those files.
See the codegen example repository for an example of using Thrift to generate Python.
Benefit of Pants: generated files are always up-to-date
With Pants, there's no need to manually regenerate your code or check it into version control. Pants will ensure you are always using up-to-date files in your builds.
Thanks to fine-grained caching, Pants will regenerate the minimum amount of code required when you do make changes.
Step 1: Activate the Thrift Python backend
Add this to your
[GLOBAL] backend_packages.add = [ "pants.backend.codegen.thrift.apache.python", "pants.backend.python", ]
You will also need to make sure that
thrift is discoverable on your PATH, as Pants does not install Thrift for you. Alternatively, you can tell Pants where to discover Thrift:
[apache-thrift] # Defaults to the special string "<PATH>", which expands to your $PATH. thrift_search_paths = ["/usr/bin"]
This backend adds the new
thrift_source target, which you can confirm by running
./pants help thrift_source.
To reduce boilerplate, you can also use the
thrift_sources target, which generates one
thrift_source target per file in the
thrift_sources(name="thrift", sources=["user.thrift", "admin.thrift"]) # Spiritually equivalent to: thrift_source(name="user", source="user.thrift") thrift_source(name="admin", source="admin.thrift") # Thanks to the default `sources` value of '*.thrift', spiritually equivalent to: thrift_sources(name="thrift")
Step 2: Set up the
thrift runtime library
Generated Python files require the
thrift dependency for their imports to work properly.
thrift to your project, e.g. your
requirements.txt (see Third-party dependencies).
Pants will then automatically add these dependencies to your
thrift_sources targets created in the next step.
Step 3: Generate
./pants tailor :: for Pants to create a
thrift_sources target wherever you have
$ ./pants tailor :: Created src/thrift/BUILD: - Add thrift_sources target thrift
Pants will use dependency inference for any
import statements in your
.thrift files, which you can confirm by running
./pants dependencies path/to/file.thrift. You should also see the
python_requirement target for the
thrift library from the previous step.
Step 4: Confirm Python imports are working
Now, you can import the generated Python modules in your Python code.
For each Thrift file, the compiler will generate at least three files
constants.py. The location of those files—and corresponding imports—depends on whether you set
namespace py in your
|unset||Files generated as top-level modules, without any prefix directories.|
|set||Files generated into the namespace.|
As shown in the table, your Python imports depend on whether the Thrift file uses
Imports behave the same regardless of whether you have source roots, such as
src/thrift. The import will still either be the top-level file like
user.ttypes or the custom namespace.
Pants's dependency inference will detect Python imports of Thrift modules, which you can confirm by running
./pants dependencies path/to/file.py.
You can also manually add the dependency:
Pants can handle Thrift regardless of whether you set
However, it's often a good idea to set the namespace because it can make your imports more predictable and declarative. It also reduces the risk of your Thrift file names conflicting with other Python modules used, such as those from third-party requirements.
For example, compare
./pants export-codegen ::to inspect the files
./pants export-codegen ::will run all relevant code generators and write the files to
dist/codegenusing the same paths used normally by Pants.
You do not need to run this goal for codegen to work when using Pants;
export-codegenis only for external consumption outside of Pants.
If you're using multiple resolves (i.e. multiple lockfiles), then you may need to set the
thrift_source targets only work with a single resolve, meaning, for example, that a
python_source target that uses the resolve 'a' can only depend on Thrift targets that also uses this same resolve.
thrift_sources targets use the resolve set by the option
[python].default_resolve. To use a different resolve, set the field
python_resolve: str to one of the values from the option
You must also make sure that any resolves that use codegen include the
python_requirement target for the
thrift runtime library from Step 2. Pants will eagerly validate this for you.
If the same Thrift files should work with multiple resolves, you can use the
python_requirement( name="thrift-requirement", # Here, we use the same version of Thrift in both resolves. You could instead create # a distinct target per resolve so that they have different versions. requirements=["thrift==0.15.0""], resolve=parametrize("resolve-a", "resolve-b"), ) thrift_sources( name="thrift", python_resolve=parametrize("resolve-a", "resolve-b") )
Updated 11 months ago