UPDATE: może to być „niemożliwe”, aby zrobić czysto ponieważ sfinks używa kodu wynikowego funkcja do generowania swój podpis funkcji. Ale ponieważ używasz sfinksa, istnieje hacky obejście, które działa.
Jest hacky, ponieważ skutecznie wyłącza dekorator, gdy sfinks działa, ale działa, więc jest to praktyczne rozwiązanie.
Najpierw poszedłem na trasę budowy nowego obiektu types.CodeType
, aby zastąpić element kodu obiektu func_code
opakowania, który jest używany przez sfinks podczas generowania sygnatur.
Udało mi się zmusić do pęknięcia pytona, pokonując trasę lub próbując zamienić elementy obiektu kodu z pierwotnej funkcji, i jednocześnie odwołując się, było to zbyt skomplikowane.
Poniżej rozwiązanie, podczas gdy jest to hacky ciężki młot, jest również bardzo proste =)
Podejście jest następujący: podczas uruchamiania wewnątrz sfinksa, ustawić zmienną środowiskową, że dekorator można sprawdzić. wewnątrz dekoratora, gdy sfinks zostanie wykryty, nie rób w ogóle dekoracji, a zamiast tego zwróć oryginalną funkcję.
Wewnątrz sfinks conf.py:
import os
os.environ['SPHINX_BUILD'] = '1'
A potem tu jest modułem przykład z testu, który pokazuje, co to może wyglądać:
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()
Dokumentacja w stdlib i Sfinksa oba wydają się sugerować że robisz wszystko dobrze. :( –
Czy próbowałeś użyć [pakietu dekoratora] (http://pypi.python.org/pypi/decorator) i umieszczając '@ decorator' na' checkStale'? Miałem podobny problem używając 'epydoc' z dekorowanym funkcja: – bstpierre
@ bstpierre Rozumiem, że pakiet dekoratora nie jest częścią normalnej dystrybucji Pythona? Zastanawiam się, czy możliwe jest użycie go tam, gdzie jest on dostępny, i w inny sposób może zastąpić to, co mam? –