2017-05-23 3 views
0

Étant donné un paquet python pack fournissant la classe pack.foo.Bar:refactorisation un module et en gardant la compatibilité ascendante, y compris pour intersphinx

pack/ 
    __init__.py # empty 
    foo.py 
   # content of foo.py 
     """ 
     This module does stuff using the :class:`pack.foo.Bar` class. 
     """ 

     class Bar(object): 
      pass 

     # much more code here 

Je veux factoriser le module pack.foo dans un paquet, de sorte que la classe Bar est déplacé le fichier pack/foo/bar.py. Afin de maintenir la compatibilité ascendante, je peux eu ce au fichier pack/foo/__init__.py:

""" 
This module does stuff using the :class:`pack.foo.Bar` class. 
""" 

from pack.foo.bar import Bar 
__all__ = ['Bar'] 

Les utilisateurs de l'API peuvent toujours utiliser from pack.foo import Bar.

Un problème subsiste: les références lors de l'utilisation du sphinx. Lorsque le docstring sphynx parse dans pack/foo/__init__.py, il ne peut pas trouver la cible:

WARNING: py:class reference target not found pack.foo.bar.Bar 

qui briserait la documentation faite par les utilisateurs lors de l'utilisation de l'extension intersphinx.

Quelle est la bonne façon de rééquiper une structure de colis tout en conservant une rétrocompatibilité complète, y compris l'inventaire des objets sphinx?

Répondre

0

Voici ma propre réponse avec quelques résultats.

Il n'y a pas de solution miracle dans cette situation.

D'abord, la documentation de code générée par sphinx-apidoc aura la disposition de module déduite de la disposition de fichier. Cela signifie que la classe Bar définie dans pack/foo.py sera documentée sous la forme pack.foo.Bar, quel que soit le mode d'importation utilisé dans pack/__init__.py. Deuxièmement, on peut toujours utiliser le autodoc extension. Autodoc essaie simplement d'importer les symboles documentés normalement lorsqu'ils sont définis dans le texte restructuré. De cette façon, vous pouvez générer des documents HTML pour la classe Bar utilisant

.. autoclass:: pack.Bar 
    :members: 

Il y a un hic cependant. Tout symbole documenté (et chacune de leurs dépendances, de manière transitoire) doit être utilisé avec le même espace de noms que celui qui est destiné à être documenté. Considérons une variante de notre exemple, en fournissant une classe supplémentaire Baz:

pack/ 
    __init__.py 
     # content of __init__.py 
   from pack.foo.bar import Bar, Baz 
     __all__ = ['Bar', 'Baz'] 

    foo.py 
     # content of foo.py 
     """ 
     This module does stuff using the :class:`pack.foo.Bar` class. 
     """ 

     class Bar(object): 
      pass 

     class Baz(Bar): # Here, sphinx thinks that Baz inherits from 
      pass   # pack.foo.Bar because Bar.__module__ is 
         # pack.foo in this context. 

Sphinx ne parviendra pas à importer pack.foo.Bar car il est importable seulement comme pack.Bar en raison du contenu de pack/__init__.py. Pour que cela fonctionne, il faut trouver un moyen d'utiliser uniquement la disposition d'importation exacte fournie par l'API du paquet dans le code de l'API lui-même. Ceci peut être réalisable, dans notre exemple par exemple, en définissant les classes Bar et Baz dans des fichiers séparés. Bonne chance et méfiez-vous des importations cycliques!