Re: flexi adaption/casting scheme - Mailing list psycopg
From | Ronan Dunklau |
---|---|
Subject | Re: flexi adaption/casting scheme |
Date | |
Msg-id | 12502020.uTbJDaCLCq@ropc Whole thread Raw |
In response to | Re: flexi adaption/casting scheme (Daniele Varrazzo <daniele.varrazzo@gmail.com>) |
Responses |
Re: flexi adaption/casting scheme
|
List | psycopg |
Le vendredi 21 septembre 2012 17:04:01 Daniele Varrazzo a écrit : > 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? It does indeed seem nice :). I would be very happy if it is included in a future release. My use case could then be implemented as the following simple mixin: class ClassComposite(psycopg2.extras.CompositeCaster): def make(self, attrs): return self.__class__(**dict(zip(self.attnames, attrs))) Thank you for the correction and the detailed explanation. Best Regards, -- Ronan Dunklau > > 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