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


psycopg by date:

Previous
From: Daniele Varrazzo
Date:
Subject: Re: flexi adaption/casting scheme
Next
From: Tobias Oberstein
Date:
Subject: Re: flexi adaption/casting scheme