Come posso sottoclassare RequestHandler per convalidare automaticamente gli argomenti?
-
21-12-2019 - |
Domanda
Ho il codice seguente:
class CounterIDHandler(RequestHandler):
@gen.coroutine
def get(self, counter_id):
try:
object_id = bson.objectid.ObjectId(counter_id)
except bson.errors.InvalidId as e:
self.finish(json_encode({'e': str(e)}))
return
# I want to finish execution here
class CounterHandler(CounterIDHandler):
@gen.coroutine
def get(self, counter_id):
super().get(counter_id)
print("this should not print if we get exception in super().get")
try:
# I want to use object_id here
except Exception as e:
self.finish(json_encode({'e': str(e)}))
Questo ovviamente non funziona ma mostra quello che sto cercando di fare.self.finish()
termina la connessione con il client ma non termina l'esecuzione.
Voglio verificare che counter_id sia un object_id valido senza copiare e incollare il codice in tutti i gestori.
Soluzione
Perché lo stai inserendo? get()
nella classe base?Mi sembra che questo dovrebbe andare in un separato get_object_id
metodo.In ogni caso, ci sono due modi in cui il metodo condiviso può influenzare il chiamante:eccezioni e il valore restituito.
Utilizzando un valore restituito pari a None per segnalare che il chiamante deve fermarsi:
class CounterIDHandler(RequestHandler):
def get_object_id(self, counter_id):
try:
return bson.objectid.ObjectId(counter_id)
except bson.errors.InvalidId as e:
self.finish(json_encode({'e': str(e)}))
return None
class CounterHandler(CounterIDHandler):
def get(self, counter_id):
object_id = self.get_object_id(counter_id)
if object_id is None:
return
O con eccezioni e a write_error
gestore:
class CounterIDHandler(RequestHandler):
def get_object_id(self, counter_id):
return bson.objectid.ObjectId(counter_id)
def write_error(self, status_code, **kwargs):
if 'exc_info' in kwargs:
typ, exc, tb = kwargs['exc_info']
if isinstance(exc, bson.errors.InvalidId):
self.finish(json_encode({'e': str(e)}))
return
super(CounterIDHandler, self).write_error(status_code, **kwargs)
class CounterHandler(CounterIDHandler):
def get(self, counter_id):
object_id = self.get_object_id()
Altri suggerimenti
Potresti creare un decoratore, qualcosa del genere (non testato):
def oid_validator(f):
@web.asynchronous
def wrapped(self, oid_str):
try:
oid = bson.objectid.ObjectId(oid_str)
except bson.errors.InvalidId as e:
self.finish(json_encode({'e': str(e)}))
else:
coro = gen.coroutine(f)
coro(self, oid)
.
Allora invece di decorare i tuoi metodi get()
con @gen.coroutine
, è possibile depositarli con @oid_validator
:
class CounterIDHandler(RequestHandler):
@oid_validator
def get(self, counter_id):
# counter_id is now an ObjectId instance
.