Обсуждение: Can't register an adapter for an "old style" python class
I need to register an adapter for the dateutil's relativedelta class. Here is what I did : In [1]: import psycopg2 In [2]: psycopg2.__version__ Out[2]: '2.4.2 (dt dec pq3 ext)' In [3]: import dateutil In [4]: dateutil.__version__ Out[4]: '1.5' In [5]: from psycopg2.extensions import adapt, adapters, register_adapter, AsIs In [6]: from dateutil.relativedelta import relativedelta In [7]: register_adapter(relativedelta, lambda v: AsIs(adapt(str(v)))) In [8]: relativedelta in [k[0] for k in adapters.keys()] Out[8]: True In [9]: adapt(relativedelta(years=+1)) --------------------------------------------------------------------------- ProgrammingError Traceback (most recent call last) /home/gl/src/MCA3/git2/<ipython console> in <module>() ProgrammingError: can't adapt type 'instance' I guess psycopg2 uses type instead of isinstance and this does not work with old-style python class : In [10]: [(isinstance(r, typ), type(r) == typ) for (typ, a), b in ....: adapters.items()] Out[10]: [(True, False), (False, False), (False, False), (False, False), [... SNIP ... ] What is the "right" way to do this ? -- Ghislain LEVEQUE - Clarisys Informatique http://www.clarisys.fr - 09 72 11 43 60
On Wed, Nov 2, 2011 at 10:56 AM, Ghislain LEVEQUE <ghislain.leveque@clarisys.fr> wrote: > I need to register an adapter for the dateutil's relativedelta class. > [...] > I guess psycopg2 uses type instead of isinstance and this does not work with > old-style python class : Yes, as far as I can see it has always worked this way: roughly there is a mapping type -> adapter in psycopg2.extensions.adapters and the adapter is looked up by adapters[type(obj)]. If we had to use isinstance instead, it would take a linear scan of the adapters map for every adapted object. So It seems psycopg has worked with new style classes since they were really new, and never bothered with old-style ones. > What is the "right" way to do this ? There are several sub-optimal ways to do it, each one flawed in some way. You could create an adapter for type(relativedelta()), being "instance" but you can do this only for one old-style class in the entire runtime. You can also create a new-style object out of it by "class MyRelativeDelta(relativedelta, object): pass", but I've checked and every operation you make on it (e.g. delta1 + delta2) will create a relativedelta instance. I would say very simply copy the dateutil module into your project, patch it to make a new style class it and use it: I think the license (PSF) allows that. Also consider filing a request to the dateutil author to make it a new-style class. Oh, it looks like you are a contributor: <https://launchpad.net/dateutil>. Why don't you make it a new-style class? There is also this, cropped up in a google search, don't know what it is: <http://pypi.python.org/pypi/psycopg2-dateutils/0.1>. -- Daniele
Le 02/11/2011 13:00, Daniele Varrazzo a écrit : > On Wed, Nov 2, 2011 at 10:56 AM, Ghislain LEVEQUE > <ghislain.leveque@clarisys.fr> wrote: >> I guess psycopg2 uses type instead of isinstance and this does not work with >> old-style python class : > > Yes, as far as I can see it has always worked this way: roughly there > is a mapping type -> adapter in psycopg2.extensions.adapters and the > adapter is looked up by adapters[type(obj)]. If we had to use > isinstance instead, it would take a linear scan of the adapters map > for every adapted object. So It seems psycopg has worked with new > style classes since they were really new, and never bothered with > old-style ones. Is it possible to (re)define 'adapt' so that it first check if type(obj) = 'instance' and then perform a scan on the mapping. Else, get the adapter the usual way ? >> What is the "right" way to do this ? > I would say very simply copy the dateutil module into your project, > patch it to make a new style class it and use it: I think the license > (PSF) allows that. Also consider filing a request to the dateutil > author to make it a new-style class. Oh, it looks like you are a > contributor:<https://launchpad.net/dateutil>. Why don't you make it a > new-style class? Well I think I'll have to do this. Thanks > There is also this, cropped up in a google search, don't know what it > is:<http://pypi.python.org/pypi/psycopg2-dateutils/0.1>. Yes, I've based my work on this code but it's incomplete (only in the SQL->python way) and I needed both ways -- Ghislain LEVEQUE - Clarisys Informatique http://www.clarisys.fr - 09 72 11 43 60
On Wed, Nov 2, 2011 at 1:28 PM, Ghislain LEVEQUE <ghislain.leveque@clarisys.fr> wrote: > Le 02/11/2011 13:00, Daniele Varrazzo a écrit : >> >> On Wed, Nov 2, 2011 at 10:56 AM, Ghislain LEVEQUE >> <ghislain.leveque@clarisys.fr> wrote: >>> >>> I guess psycopg2 uses type instead of isinstance and this does not work >>> with >>> old-style python class : >> >> Yes, as far as I can see it has always worked this way: roughly there >> is a mapping type -> adapter in psycopg2.extensions.adapters and the >> adapter is looked up by adapters[type(obj)]. If we had to use >> isinstance instead, it would take a linear scan of the adapters map >> for every adapted object. So It seems psycopg has worked with new >> style classes since they were really new, and never bothered with >> old-style ones. > > Is it possible to (re)define 'adapt' so that it first check if type(obj) = > 'instance' and then perform a scan on the mapping. Else, get the adapter the > usual way ? It is definitely possible, but I don't feel it urgent: I don't see any reason to still be using old-style classes, new ones offer only advantages (such as having a type, dateutil objects could use __slots__ etc.), they have been around since about 2002 and never since adapters for old style classes have been requested. Old style classes have been phased out since Python 3.0. Said this, the check for an object being an old-style class instance is probably very lightweight (not much more than a pointer comparison in C), so if a patch was submitted to introduce it I wouldn't be against including it. The code is in microprotocols.c. >> Also consider filing a request to the dateutil >> author to make it a new-style class. Oh, it looks like you are a >> contributor:<https://launchpad.net/dateutil>. Why don't you make it a >> new-style class? > > Well I think I'll have to do this. Thanks I honestly think it would be globally a better gain than making psycopg2 old-style classes aware. -- Daniele