python / python/mypy

stubgen and Cython modules

Ouverte
#7,542 7 commentaires 9 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

feature priority-1-normal topic-stubgen
Langage dominant
Python
Étoiles
20.6k
Forks
3.3k
Merge moyen
1 j 18 h
PR mergées (30 j)
54

Description

Hello,

I'm trying to use mypy with a Cython module (via stubgen).

Example Cython module (test.pyx):

import typing

def f(path: str, a: int = 0, b: bool = True) -> typing.List[str]:
    return []

cdef class MyClass(object):
    def __init__(self, name: str = None):
        self.name = name

    def run(self, action: str) -> None:
        pass

Compile this module: cythonize -b test.pyx
The output will be a binary extension module (test..pyd/test..so).
Run stubgen on this via stubgen -m test.

In general, there's two ways in which Cython can expose the function signature:

  • #cython: embedsignature=True: Cython will embed the signature in the docstring. This has some issues in Cython, see cython/cython#3150.
  • #cython: binding=True: Cython will use a custom function object (not a PyCFunction) that has the relevant attributes set -- this allows using inspect.signature(). As of Cython 3, this option is enabled by default, and I'll only consider this option in the following.

Both f and MyClass.run are of type cython_function_or_method, which is neither a Python builtin function, nor a PyCFunction.
Instead, it's effectively a custom callable that has most of the attributes expected for a function:

>>> dir(test.f)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__vectorcalloffset__', '_is_coroutine', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
>>> test.f.__annotations__
{'path': 'str', 'a': 'int', 'b': 'bool', 'return': 'typing.List[str]'}
>>> inspect.signature(test.MyClass.run)
<Signature (self, action: 'str') -> 'None'>

However stubgen fails to correctly handle this custom callable, and ends creating:

import _cython_3_1_3

__test__: dict
f: _cython_3_1_3.cython_function_or_method

class MyClass:
    def __init__(self, *args, **kwargs) -> None: ...
    def run(self, *args, **kwargs): ...
    def __reduce__(self): ...
    def __reduce_cython__(self, *args, **kwargs): ...
    def __setstate_cython__(self, *args, **kwargs): ...

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par reproduire l’exemple avec le module Cython et stubgen -m test, puis suivez la façon dont stubgen gère les objets cython_function_or_method et les signatures exposées via __annotations__ et inspect.signature(). C’est terminé lorsque les stubs générés préservent les signatures indiquées pour f et MyClass.run au lieu d’utiliser des arguments Callable génériques.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
tooling
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
42/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.