Re: JSON type caster

From: Daniele Varrazzo <daniele(dot)varrazzo(at)gmail(dot)com>
To: Tobias Oberstein <tobias(dot)oberstein(at)gmail(dot)com>
Cc: psycopg(at)postgresql(dot)org
Subject: Re: JSON type caster
Date: 2012-09-19 13:12:56
Message-ID: CA+mi_8Yv2SVOdhAtx-4CbpzoDtaJGkf8QvnushdF8bMgySAbYg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: psycopg

On Wed, Sep 19, 2012 at 1:36 PM, Tobias Oberstein
<tobias(dot)oberstein(at)gmail(dot)com> wrote:

> A minor inconvenience: when on PG 9.2 OIDs are well know, but when
> I need to register a custom JSON typecaster, I nevertheless need
> to supply the OIDs _or_ provide a connection (which I may want
> to avoid when I want the behavior globally):
>
> loads = lambda x: json.loads(x, parse_float = Decimal)
> psycopg2.extras.register_json(None, globally = True, loads = loads, oid =
> 114, array_oid = 199)
> #psycopg2.extras.register_json(None, globally = True, loads = loads) # won't
> work
>
> I am fine with that, but the example in the docs would probably profit
> from mentioning this code snippet .. "how to install custom JSON typecaster
> on PG92 globally".

Oh, yes, I see the use case. You are right, it's too tricky for its
usefulness. The easiest (for us) solution would be to provide symbolic
constants in psycopg2.extensions. It results in a still too verbose:

psycopg2.extras.register_json(None, globally=True, loads=loads,
oid=ext.JSON_OID, array_oid=ext.JSONARRAY_OID)

btw there's too use for the conn_or_curs=None: I think I'll set it as
default so that it can be dropped if only kwargs are provided. The
above would become:

psycopg2.extras.register_json(globally=True, loads=loads,
oid=ext.JSON_OID, array_oid=ext.JSONARRAY_OID)

Uhm... but what about a new function? To be called

psycopg2.extras.register_default_json(globally=True, loads=loads)

or
conn = psycopg2.connect(...)
psycopg2.extras.register_default_json(conn, loads=loads)

To be implemented like:

def register_default_json(conn_or_curs=None, globally=False, loads=None):
"""Register json adapter for PG92 and following"""
return register_json(conn_or_curs=conn_or_curs,
globally=globally, loads=loads,
oid=114, array_oid=199)

> Another thing that's probably inconvenient: psycopg2.extras.Json
> forwards kwargs for customization, but there is no trivial way
> of using a different "json" implementation altogether

What I didn't like reviewing the two sides is the asymmetry: adapter
taking **kwargs and typecaster taking loads function. I'm thinking
about passing a dumps function instead of the **kwargs. It could be:

class Json(object):
def __init__(self, adapted, dumps=None):
self.adapted = adapted
self._dumps = dumps is None and json.dumps or dumps

def dumps(self):
return self._dumps(self.adapted)

def getquoted(self):
s = self.dumps()
return QuotedString(s).getquoted()

This way customization can be performed either functional-style via a closure:

def CustomJson(adapted):
return Json(adapted,
dumps=lambda x: simplejson.dumps(x, parse_float=Decimal))

or oo-style via subclassing:

class CustomJson(Json):
def dumps(self)
return simplejson.dumps(self.adapted, parse_float=Decimal)

Thank you for the review. Comments?

-- Daniele

In response to

Responses

Browse psycopg by date

  From Date Subject
Next Message Tobias Oberstein 2012-09-19 13:42:33 Re: JSON type caster
Previous Message Tobias Oberstein 2012-09-19 12:36:11 Re: JSON type caster