Back in December, when I released rush, I struggled to figure out the appropriate way to signal that the library was shipping with type annotations built-in. I've also been working on adding type annotation stub files to github3.py as a result, I've had to look around quite a bit for the magic incantations that tell mypy and other pieces of software:
- to include the .pyi stub files (when necessary)
- and that the annotations are included
Let's take this in a few steps:
How do you include stub files?
This is less of an issue with the PEPs and more of knowing how to use setuptools.
In your setup.py or setup.cfg file, you can specify extra data to be included in the package, a.k.a. package_data. You may already have something that looks like:
setup(
name='mypackage',
# ...
package_data={
'mypackage': ['*.json'],
},
include_package_data=True,
# ...
)
This is instructing setuptools (in this example) to include JSON files found inside of your package. Now you'll want to extend that list to include a glob pattern for your .pyi files, e.g.,
setup(
name='mypackage',
# ...
package_data={
'mypackage': ['*.json', '*.pyi'],
},
include_package_data=True,
# ...
)
How do you indicate annotations are included?
This is indicated by placing a file named py.typed in your module. For example, in rush's case this looks like an empty file with the (git) path of src/rush/py.typed. When installed this translates to rush/py.typed in your file system.
This file is specified in PEP 561 and referenced in PEP 484. To ensure this is also included with your package when distributed you'll need to - you guessed it - add it to your package_data list. If you have .pyi stub files your usage would look like:
setup(
name='mypackage',
# ...
package_data={
'mypackage': ['*.json', '*.pyi', 'py.typed'],
},
include_package_data=True,
# ...
)
What if you are using setup.cfg?
Well in that case you would want to follow rush's example a bit more closely. Specifically, you'll want to have options and options.package_data sections:
[metadata]
name = mypackage
[options]
; ...
include-package-data = True
[options.package_data]
mypackage = py.typed