asweigart / pyperclip

Python module for cross-platform clipboard functions.
https://pypi.python.org/pypi/pyperclip
BSD 3-Clause "New" or "Revised" License
1.6k stars 193 forks source link

Add type hinting stub file #255

Open jpgoldberg opened 4 months ago

jpgoldberg commented 4 months ago

Resolve #210

This adds a type hinting stub file, src/init.pyi, which includes type hinted function signatures for the public functions of the packages. It also includes the py.typed file as a marker saying that type hinting information is available from the package.

The problem

Currently when running mypy on a python source file that imports pyperclip will result in a type checking error

% mypy pyper-example.py                  
pyper-example.py:1: error: Skipping analyzing "pyperclip": module is installed, but missing library stubs or py.typed marker  [import-untyped]
pyper-example.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
Found 1 error in 1 file (checked 1 source file)

There are ways that users can work around or ignore the error, but having to do so increases the chances that users will not type check their own code as well as they otherwise would.

The fix

We create a stub with correct type hinting and add a py.typed marker.

The relevant PEPs are 484 and 561.

With the fixed version:

 % mypy pyper-example.py 
Success: no issues found in 1 source file

Decisions made and their rationales

  1. Maintain backwards compatibility.

    paperclip must continue to work out of the box with all of the source published with Al Swiegart's books and material. Only those who seek to run static type checkers on code that imports pyperclip should notice any change. This is why the type hints are provided in the form of a PEPs 484 and 561 stub file.

  2. __all__ functions instead of all functions

    The stub file includes signatures for all and only those listed in __all__ functions provided by the module. This seems fully in line with the intention of __all__

  3. timeout is a float.

    Although most usages of timeout will be int's time, a float is maximally permissive while remaining compatible with the return type of time.time()

  4. Text in py.typed

    The existence of a py.typed file (PEP 561) is used to tell type checkers that there is type hinting information available. The file may be empty, but because the type hints are in a stub file instead of in line in the source, I added some text in that file to help humans find the type hinting information.

Before releasing

This PR does not touch the change log nor the version information. Those ought to be handled by the package maintainer.