Come posso sottoclassare RequestHandler per convalidare automaticamente gli argomenti?

StackOverflow https://stackoverflow.com//questions/23012316

  •  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.

È stato utile?

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
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top