Re: flexi adaption/casting scheme - Mailing list psycopg
From | Daniele Varrazzo |
---|---|
Subject | Re: flexi adaption/casting scheme |
Date | |
Msg-id | CA+mi_8bU6y5rEj2k9NfoXqKmbBzQp=f0Um7nVMxuy4X1RQCxTg@mail.gmail.com Whole thread Raw |
In response to | Re: flexi adaption/casting scheme (Ronan Dunklau <rdunklau@gmail.com>) |
Responses |
Re: flexi adaption/casting scheme
Re: flexi adaption/casting scheme |
List | psycopg |
On Fri, Sep 21, 2012 at 2:47 PM, Ronan Dunklau <rdunklau@gmail.com> wrote: >> 1.3 >> composite type => plain Python dict with key/value pairs only >> for all attributes in the composite type that have non-NULL values > > It would be great to have an API to customize the class to instantiate with a > composite type. > > I tried an implementation in the attached patch. > > The idea would be to add an optional "ctor" argument, which would be used in > place of the namedtuple argument. Additionally, an adapter can be > automatically registered to perform the reverse conversion. Thank you, I like the idea of customizing the composite caster. But I don't like very much the proposed way. Oddly enough, just yesterday I've changed the _ctor: it used to take *args instead of an iterable of args but I've just recently discovered namedtuple._make which has the same signature of the basic tuple and can be used to avoid unpacking. You patch puts it back to "self._ctor = lambda *args: tuple(args)" and then some. Your patch passes the arguments to the ctor in the most generic way (as **kwargs) in order to work with any possible function, but this is overkilling for the basic use with tuple/namedtuple. And still wouldn't be enough: you can't make an OrderedDict out of it for instance, as **kwargs randomizes the order. I propose the attached diff instead. It makes the CompositeCaster easy to subclass and exposes part of the machinery used by register_composite() in order to make the class registrable without adding new arguments to register_composite() too, which would only deal with the basic case. Customization is performed overriding the method "make" which takes the attributes read from the db in input. Attribute names can be obtained from "self". For example, to cast composite to dictionaries one can subclass it as: class DictComposite(psycopg2.extras.CompositeCaster): def make(self, attrs): return dict(zip(self.attnames, attrs)) Which would be used as: # from psql: CREATE TYPE card AS (value int, suit text); c = DictComposite.from_db('card', cnn) c.register() cur.execute("select (8, 'hearts')::card") cur.fetchone()[0] {'suit': 'hearts', 'value': 8} Seems nice, doesn't it? Tobias: as expected it works ok with composite types, as the original CompositeCaster does: # from psql: CREATE TYPE card_back AS (face card, back text); c2 = DictComposite.from_db('card_back', cnn) c2.register() cur.execute("select ((8, 'hearts'), 'blue')::card_back") cur.fetchone()[0] {'back': 'blue', 'face': {'suit': 'hearts', 'value': 8}} if it doesn't work for you, you are probably doing something wrong. -- Daniele