Обсуждение: Can't register an adapter for an "old style" python class

Поиск
Список
Период
Сортировка

Can't register an adapter for an "old style" python class

От
Ghislain LEVEQUE
Дата:
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


Re: Can't register an adapter for an "old style" python class

От
Daniele Varrazzo
Дата:
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

Re: Can't register an adapter for an "old style" python class

От
Ghislain LEVEQUE
Дата:
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


Re: Can't register an adapter for an "old style" python class

От
Daniele Varrazzo
Дата:
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