更新: 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()