Features

This document describes how pygenstub generates the stub files from the source.

Methods

Methods are handled the same way as functions except that there is no type hint for the self parameter (assuming it’s the first parameter):

code:
class Foo:
    def foo(self, a):
        """Do foo.

        :sig: (int) -> None
        """
stub:
class Foo:
    def foo(self, a: int) -> None: ...

Imported names

Imported type names in the source will be used in the stub file if needed:

code:
from x import A, B, C

def foo(a, b):
    """Do foo.

    :sig: (A, B) -> A
    """
stub:
from x import A, B

def foo(a: A, b: B) -> A: ...

Note that the name C is not imported in the stub file.

Qualified names

Qualified (dotted) type names will generate import lines in the stub file if they are not already imported:

code:
from z import x

def foo(a, b):
    """Do foo.

    :sig: (x.A, y.B) -> m.n.C
    """
stub:
from z import x
import y
import m.n

def foo(a: x.A, b: y.B) -> m.n.C: ...

Names from the typing module

Unresolved names will be looked up in the typing module.

code:
def foo(a, b):
    """Do foo.

    :sig: (List[int], Mapping[str, int]) -> Iterable[str]
    """
stub:
from typing import Iterable, List, Mapping

def foo(a: List[int], b: Mapping[str, int]) -> Iterable[str]: ...

Default values

If a parameter has a default value, the prototype will contain the triple dots placeholder for it:

code:
def foo(a, b=''):
    """Do foo.

    :sig: (int, str) -> None
    """
stub:
def foo(a: int, b: str = ...) -> None: ...

Base classes

The imports needed for base classes will be included or generated using the same rules as described above (imported, dotted, etc.):

code:
from x import A

class Foo(A, y.B):
    def foo(self, a):
        """Do foo.

        :sig: (int) -> None
        """
stub:
from x import A
import y

class Foo(A, y.B):
    def foo(self, a: int) -> None: ...

Class signatures

If the docstring of a class has a signature field, it will be used as the signature field of its __init__ method unless that method already has a signature.

code:
class Foo:
    """A foo.

    :sig: (int) -> None
    """

    def __init__(self, a):
        self.a = a
stub:
class Foo:
    def __init__(self, a: int) -> None: ...

Signature comments

Type hints for assignments can be written using # sig: comments.

code:
n = 42  # sig: int
stub:
n = ...  # type: int

The rules for importing names as described above also apply here.

Note

The reason for using # sig comment instead of a # type comment would be to avoid having to import the types.

Instance variables

Within classes, assignments to attributes of self will generate assignments with type comments under the class:

code:
class Foo:
    def foo(self):
        self.y = 'spam'  # sig: str
stub:
class Foo:
    y = ...  # type: str

Long lines

If the prototype line gets too long, it will be divided into multiple lines:

code:
def some_long_func_name(some_long_param_name_1, some_long_param_name_2):
    """Do foo.

    :sig: (some_long_type_1, some_long_type_2) -> some_long_type_3
    """
stub:
def some_long_func_name(
    some_long_param_name_1: some_long_type_1,
    some_long_param_name_2: some_long_type_2,
) -> some_long_type_3: ...

Type aliases

Type aliases can be defined using a # sigalias comment:

code:
# sigalias: A = int

def foo(a):
    """Do foo.

    :sig: (A) -> None
    """
stub:
A = int

def foo(a: A) -> None: ...