31

Sphinx を使用して Python クラスを文書化しようとしています。私は autodoc を使用してそうします:

.. autoclass:: Bus
   :members:

私のメソッドのdocstringを正しくフェッチしますが、装飾されたものは次のとおりです。

    @checkStale
    def open(self):
        """
        Some docs.
        """
        # Code

@checkStaleありながら

def checkStale(f):
    @wraps(f)
    def newf(self, *args, **kwargs):
        if self._stale:
            raise Exception
        return f(self, *args, **kwargs)
    return newf

などの間違ったプロトタイプを持っているopen(*args, **kwargs)

どうすればこれを修正できますか? @wrapsを使用すると、このようなことが修正されるという印象を受けました。

4

6 に答える 6

15

セロリ @task デコレータでも同じ問題がありました。

次のように、最初のファイルに正しい関数シグネチャを追加することで、これを修正することもできます。

.. autoclass:: Bus
    :members:

    .. automethod:: open(self)
    .. automethod:: some_other_method(self, param1, param2)

非デコレータ メンバーは引き続き自動的にドキュメント化されます。

これはhttp://www.sphinx-doc.org/en/master/ext/autodoc.html#directive-automoduleの sphinx のドキュメントに記載されています。デコレーター。」

私の場合、autofunction を使用して、django アプリの tasks.py モジュールでセロリ タスクの署名を指定する必要がありました。

.. automodule:: django_app.tasks
    :members:
    :undoc-members:
    :show-inheritance:

    .. autofunction:: funct1(user_id)
    .. autofunction:: func2(iterations)
于 2013-03-28T22:11:40.287 に答える
14

私のコメントを拡張するには:

デコレータ パッケージを使用して @decorator を checkStale に設定してみましたか? 装飾された関数でepydocを使用すると、同様の問題が発生しました。

コメントで尋ねたように、decorator パッケージは標準ライブラリの一部ではありません。

次のようなコードを使用してフォールバックできます (テストされていません)。

try:
    from decorator import decorator
except ImportError:
    # No decorator package available. Create a no-op "decorator".
    def decorator(f):
        return f
于 2010-09-12T19:52:47.407 に答える
3

バージョン 1.1 で追加され、docstring の最初の行にカスタム値を指定することで、メソッド シグネチャをオーバーライドできるようになりました。

http://sphinx-doc.org/ext/autodoc.html#confval-autodoc_docstring_signature

@checkStale
def open(self):
    """
    open()
    Some docs.
    """
    # Code
于 2012-11-06T20:34:43.837 に答える
1

別の依存関係を追加しないことに特に固執している場合は、docstring に挿入することで通常のインスペクターと連携するコード スニペットを次に示します。別のモジュールを追加しない正当な理由がない限り、これは非常にハッキーであり、実際には推奨されませんが、ここにあります。

# inject the wrapped functions signature at the top of a docstring
args, varargs, varkw, defaults = inspect.getargspec(method)
defaults = () if defaults is None else defaults
defaults = ["\"{}\"".format(a) if type(a) == str else a for a in defaults]
l = ["{}={}".format(arg, defaults[(idx+1)*-1]) if len(defaults)-1 >= idx else arg for idx, arg in enumerate(reversed(list(args)))]
if varargs: allargs.append('*' + varargs)
if varkw: allargs.append('**' + varkw)
doc = "{}({})\n{}".format(method.__name__, ', '.join(reversed(l)), method.__doc__)
wrapper.__doc__ = doc
于 2013-03-14T15:58:58.620 に答える
0

更新: sphinx は関数のコード オブジェクトを使用して関数シグネチャを生成するため、これをきれいに行うのは「不可能」である可能性があります。ただし、Sphinx を使用しているため、機能するハックな回避策があります。

スフィンクスの実行中にデコレータを効果的に無効にするため、ハッキーですが、機能するため、実用的なソリューションです。

types.CodeType最初に、署名を生成するときに sphinx が使用する、ラッパーのfunc_codeコード オブジェクト メンバーを置き換えるために、新しいオブジェクトを構築するルートをたどりました。

co_varnamesルートをたどったり、元の関数からコードオブジェクトの、co_nlocalsなどのメンバーをスワップインしようとしたりして、python のセグメンテーションができました。

次の解決策は、ハッキーで重いハンマーですが、非常に単純です =)

アプローチは次のとおりです。sphinx 内で実行する場合、デコレーターがチェックできる環境変数を設定します。デコレータの内部では、スフィンクスが検出された場合、装飾をまったく行わず、代わりに元の関数を返します。

sphinx conf.py 内:

import os
os.environ['SPHINX_BUILD'] = '1'

次に、モジュールの例と、それがどのように見えるかを示すテスト ケースを示します。

import functools
import os
import types
import unittest


SPHINX_BUILD = bool(os.environ.get('SPHINX_BUILD', ''))


class StaleError(StandardError):
    """Custom exception for staleness"""
    pass


def check_stale(f):
    """Raise StaleError when the object has gone stale"""

    if SPHINX_BUILD:
        # sphinx hack: use the original function when sphinx is running so that the
        # documentation ends up with the correct function signatures.
        # See 'SPHINX_BUILD' in conf.py.
        return f

    @functools.wraps(f)
    def wrapper(self, *args, **kwargs):
        if self.stale:
            raise StaleError('stale')

        return f(self, *args, **kwargs)
    return wrapper


class Example(object):

    def __init__(self):
        self.stale = False
        self.value = 0

    @check_stale
    def get(self):
        """docstring"""
        return self.value

    @check_stale
    def calculate(self, a, b, c):
        """docstring"""
        return self.value + a + b + c


class TestCase(unittest.TestCase):

    def test_example(self):

        example = Example()
        self.assertEqual(example.get(), 0)

        example.value = 1
        example.stale = True
        self.assertRaises(StaleError, example.get)

        example.stale = False
        self.assertEqual(example.calculate(1, 1, 1), 4)


if __name__ == '__main__':
    unittest.main()
于 2011-10-14T01:20:14.707 に答える