2013-01-04 4 views
9

Ho bisogno di classe di risposta delle richieste monkeypatch (versione 1.0.4, corrente come di questa domanda), per aggiungere ulteriori metodi.Patching scimmia Python

ho questo codice:

import requests 

class Response(requests.models.Response): 
    def hmm(self): 
     return 'ok' 

requests.models.Response = Response 

r = requests.get('http://bbc.co.uk') 

print r 

Viene a mancare quando la risposta originale prevede super() - https://github.com/kennethreitz/requests/blob/master/requests/models.py#L391

Credo che questo sia perché si confonde, come ho sostituito la classe, mi sento come sto facendo qualcosa di sciocco, qualche idea? Grazie in anticipo.

+0

In [2]: le richieste .__ version__ Out [2]: '1.0.4' È vero anche per te? Questo codice funzionava per me con una versione precedente di richieste – user964375

+0

Errore con quale errore? – Eloff

+0

File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/models.py", riga 391, in __init__ super (Response, self) .__ init __() TypeError: super (type, obj): obj deve essere un'istanza o sottotipo di tipo – user964375

risposta

12

Faresti meglio solo aggiungendo la funzione direttamente alla classe:

def hmm(self): 
    return 'ok' 
requests.models.Response.hmm = hmm 

Questo funziona bene:

>>> import requests 
>>> def hmm(self): 
...  return 'ok' 
... 
>>> requests.models.Response.hmm = hmm 
>>> r = requests.get('http://bbc.co.uk') 
>>> print r 
<Response [200]> 
>>> r.hmm() 
'ok' 
>>> requests.__version__ 
'1.0.4' 
+0

So che Pythonistas __hate__ OOP, ma per quanto riguarda la sottoclasse? – tenfishsticks

+0

@tenfishsticks: dovresti comunque sostituire la classe 'Response' con quella sottoclasse poiché le API' requests' restituiranno le istanze di quella classe. Per aggiungere un metodo, è più semplice aggiungere il metodo alla classe esistente. –

4

Io non credo che si può scimmia-patch che tipo come quello. Quando si importa requests, tutti i moduli these sono inizializzati. E poiché l'intera libreria utilizza più e più volte from xy import Request, avrà un riferimento esatto al tipo effettivo. E solo dopo, sostituisci il tipo di risposta all'interno del modulo dei modelli, quindi sono interessate solo le importazioni successive.

Se non si utilizzano tutti i moduli e si sostituisce manualmente il riferimento di risposta con il nuovo tipo, verrà comunque utilizzato quello originale, rendendo inutilizzabile la patch.

Invece, dovresti mantenere il tipo originale ma espanderlo direttamente, come suggeriva Martijn.

+0

Grazie. Userò inspect.getmembers per prendere tutti i metodi dalla mia classe e assegnarli alla classe originale. Leggermente meno elegante, ma funzionerà. – user964375

1

solo una soluzione rapida utilizzando setattr, ma è un po 'brutto (ma semanticamente equivalente a @Martijn answer):

def hmm(self): 
    return 'OK - %s' % self.status_code 

setattr(requests.models.Response, 'hmm', hmm) 

r = requests.get('http://bbc.co.uk') 
print r.hmm() 
# prints 
# OK - 200