39

I'm writing a Python project which is published as a package to a pypi-like repository (using setuptools and twine). I use type hints in my code.

The issue is, when importing the package from a different project and running mypy, I get the following error: error: Skipping analyzing 'XXX': found module but no type hints or library stubs

As I understand, I got this error because my package was not compliant with https://www.python.org/dev/peps/pep-0561/ .

After some searching online, I didn't find a way that was not manual to add the required files to the package.

I resorted to writing my own code to:

  1. Run stubgen to create stub files.
  2. Create py.typed files in every directory.
  3. Collect all the created files in a dict in package_data field in the setup.py file.

This code solved the issue and mypy runs without errors. But this feels very wrong to me. Is there a standard tool for making a package PEP-561 compliant? Am I missing something else?

Tsah Weiss
  • 563
  • 1
  • 6
  • 12
  • 6
    Have you tried skipping step 1 and simplifying step 3 so you only include the `py.typed` file in the `package_data` field? If there's a `py.typed` file and no stub files, type checkers such as mypy are supposed to analyze your source code directly to grab type hints. – Michael0x2a Jul 21 '20 at 00:27
  • 1
    That's a nice optimization, but ultimately I still have to write custom code. Also, generating stubs is the easy part, since there's a tool for that. – Tsah Weiss Jul 21 '20 at 13:13
  • 2
    I don't think you need to be writing any custom code? You should need to create only a single `py.typed` file at the top-level package and tweak your `setup.py` file once to hard-code the path to the new file. The presence of the `py.typed` file in the top-level package will imply that all subpackages must be analyzed by the type checker. Taking a closer look at your step two, it seems what you're doing instead is adding a `py.typed` file in each directory? If so, that shouldn't be necessary. – Michael0x2a Jul 21 '20 at 19:01

2 Answers2

25

As mentioned before, You need to add the py.typed in the package folder of the module. You also need to add that file to the setup.py package_data - otherwise the file would not be part of the package when You deploy it.

I personally put the type annotations in the code and dont create extra stub files - but that is only possible from python 3.4 upwards. If You want to make python2.7 compatible code, You can not use inline type annotation - in that case You can use stub files.

If You want to type annotate a third party library, You can write a *.pyi file for the functions You use for that library. That can be a bit tricky, because MYPY must only find that *.pyi file ONCE in the MYPY Path.

So I handle it that way :

for local testing, the MYPY path is set to a directory were I collect all the 3rd party stubs, for testing on travis, I have a subdirectory in the package with the stubs needed for that module to test it on travis, and set the mypy path accordingly.

bitranox
  • 1,664
  • 13
  • 21
  • Creating the file at the root of the main package (`/py.typed`) or adding `include /py.typed` in a new line to `MANIFEST.in` file in the directory will also ensure that the `py.typed` file is part of the package. – CypherX May 20 '22 at 20:51
14

The solution was to add one py.typed file to the root of the main package. This forces mypy to analyze the types.

Tsah Weiss
  • 563
  • 1
  • 6
  • 12