UPDATE: questo può essere "impossibile" per fare in modo pulito perché sfinge utilizza codice oggetto della funzione di generare la sua firma la funzione. Ma, dal momento che stai usando la sfinge, c'è una soluzione hacky che funziona.
È hacky perché disattiva efficacemente il decoratore mentre la sfinge è in esecuzione, ma funziona, quindi è una soluzione pratica.
Inizialmente ho intrapreso la strada della costruzione di un nuovo oggetto types.CodeType
, per sostituire il membro dell'oggetto codice func_code
del wrapper, che è ciò che la sfinge utilizza durante la generazione delle firme.
Sono stato in grado di segfault python scendendo lungo il percorso o tentando di scambiare i membri co_varnames
, co_nlocals
, ecc. Dell'oggetto codice dalla funzione originale, e mentre accattivante, era troppo complicato.
La seguente soluzione, mentre è un pesante martello hacky, è anche molto semplice =)
L'approccio è il seguente: durante l'esecuzione all'interno sphinx, impostare una variabile di ambiente che il decoratore può controllare. all'interno del decoratore, quando viene rilevata la sfinge, non eseguire alcuna decorazione e restituire la funzione originale.
All'interno della vostra sfinge conf.py:
import os
os.environ['SPHINX_BUILD'] = '1'
E poi qui è un modulo di esempio con un banco di prova che mostra quello che potrebbe essere simile:
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()
La documentazione nel stdlib e Sfinge entrambi sembrano implicare che stai facendo tutto bene. :( –
Hai provato a usare il [pacchetto decoratore] (http://pypi.python.org/pypi/decorator) e a mettere '@ decorator' su' checkStale'? Ho avuto un problema simile usando 'epydoc' con una decorata – bstpierre
@bstpierre Suppongo che il pacchetto decoratore non faccia parte di una normale distribuzione Python? Mi chiedo se sia possibile usarlo dove disponibile, e altrimenti rimando a quello che ho? –