Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Travis
committed
Mar 20, 2014
0 parents
commit e476d8b
Showing
36 changed files
with
11,667 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
"""A Python driver for PostgreSQL | ||
psycopg is a PostgreSQL_ database adapter for the Python_ programming | ||
language. This is version 2, a complete rewrite of the original code to | ||
provide new-style classes for connection and cursor objects and other sweet | ||
candies. Like the original, psycopg 2 was written with the aim of being very | ||
small and fast, and stable as a rock. | ||
Homepage: http://initd.org/projects/psycopg2 | ||
.. _PostgreSQL: http://www.postgresql.org/ | ||
.. _Python: http://www.python.org/ | ||
:Groups: | ||
* `Connections creation`: connect | ||
* `Value objects constructors`: Binary, Date, DateFromTicks, Time, | ||
TimeFromTicks, Timestamp, TimestampFromTicks | ||
""" | ||
# psycopg/__init__.py - initialization of the psycopg module | ||
# | ||
# Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> | ||
# | ||
# psycopg2 is free software: you can redistribute it and/or modify it | ||
# under the terms of the GNU Lesser General Public License as published | ||
# by the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# In addition, as a special exception, the copyright holders give | ||
# permission to link this program with the OpenSSL library (or with | ||
# modified versions of OpenSSL that use the same license as OpenSSL), | ||
# and distribute linked combinations including the two. | ||
# | ||
# You must obey the GNU Lesser General Public License in all respects for | ||
# all of the code used other than OpenSSL. | ||
# | ||
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT | ||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
# License for more details. | ||
|
||
# Import modules needed by _psycopg to allow tools like py2exe to do | ||
# their work without bothering about the module dependencies. | ||
|
||
# Note: the first internal import should be _psycopg, otherwise the real cause | ||
# of a failed loading of the C module may get hidden, see | ||
# http://archives.postgresql.org/psycopg/2011-02/msg00044.php | ||
|
||
# Import the DBAPI-2.0 stuff into top-level module. | ||
|
||
from psycopg2._psycopg import BINARY, NUMBER, STRING, DATETIME, ROWID | ||
|
||
from psycopg2._psycopg import Binary, Date, Time, Timestamp | ||
from psycopg2._psycopg import DateFromTicks, TimeFromTicks, TimestampFromTicks | ||
|
||
from psycopg2._psycopg import Error, Warning, DataError, DatabaseError, ProgrammingError | ||
from psycopg2._psycopg import IntegrityError, InterfaceError, InternalError | ||
from psycopg2._psycopg import NotSupportedError, OperationalError | ||
|
||
from psycopg2._psycopg import _connect, apilevel, threadsafety, paramstyle | ||
from psycopg2._psycopg import __version__ | ||
|
||
from psycopg2 import tz | ||
|
||
|
||
# Register default adapters. | ||
|
||
import psycopg2.extensions as _ext | ||
_ext.register_adapter(tuple, _ext.SQL_IN) | ||
_ext.register_adapter(type(None), _ext.NoneAdapter) | ||
|
||
# Register the Decimal adapter here instead of in the C layer. | ||
# This way a new class is registered for each sub-interpreter. | ||
# See ticket #52 | ||
try: | ||
from decimal import Decimal | ||
except ImportError: | ||
pass | ||
else: | ||
from psycopg2._psycopg import Decimal as Adapter | ||
_ext.register_adapter(Decimal, Adapter) | ||
del Decimal, Adapter | ||
|
||
import re | ||
|
||
def _param_escape(s, | ||
re_escape=re.compile(r"([\\'])"), | ||
re_space=re.compile(r'\s')): | ||
""" | ||
Apply the escaping rule required by PQconnectdb | ||
""" | ||
if not s: return "''" | ||
|
||
s = re_escape.sub(r'\\\1', s) | ||
if re_space.search(s): | ||
s = "'" + s + "'" | ||
|
||
return s | ||
|
||
del re | ||
|
||
|
||
def connect(dsn=None, | ||
database=None, user=None, password=None, host=None, port=None, | ||
connection_factory=None, cursor_factory=None, async=False, **kwargs): | ||
""" | ||
Create a new database connection. | ||
The connection parameters can be specified either as a string: | ||
conn = psycopg2.connect("dbname=test user=postgres password=secret") | ||
or using a set of keyword arguments: | ||
conn = psycopg2.connect(database="test", user="postgres", password="secret") | ||
The basic connection parameters are: | ||
- *dbname*: the database name (only in dsn string) | ||
- *database*: the database name (only as keyword argument) | ||
- *user*: user name used to authenticate | ||
- *password*: password used to authenticate | ||
- *host*: database host address (defaults to UNIX socket if not provided) | ||
- *port*: connection port number (defaults to 5432 if not provided) | ||
Using the *connection_factory* parameter a different class or connections | ||
factory can be specified. It should be a callable object taking a dsn | ||
argument. | ||
Using the *cursor_factory* parameter, a new default cursor factory will be | ||
used by cursor(). | ||
Using *async*=True an asynchronous connection will be created. | ||
Any other keyword parameter will be passed to the underlying client | ||
library: the list of supported parameters depends on the library version. | ||
""" | ||
items = [] | ||
if database is not None: | ||
items.append(('dbname', database)) | ||
if user is not None: | ||
items.append(('user', user)) | ||
if password is not None: | ||
items.append(('password', password)) | ||
if host is not None: | ||
items.append(('host', host)) | ||
if port is not None: | ||
items.append(('port', port)) | ||
|
||
items.extend([(k, v) for (k, v) in kwargs.iteritems() if v is not None]) | ||
|
||
if dsn is not None and items: | ||
raise TypeError( | ||
"'%s' is an invalid keyword argument when the dsn is specified" | ||
% items[0][0]) | ||
|
||
if dsn is None: | ||
if not items: | ||
raise TypeError('missing dsn and no parameters') | ||
else: | ||
dsn = " ".join(["%s=%s" % (k, _param_escape(str(v))) | ||
for (k, v) in items]) | ||
|
||
conn = _connect(dsn, connection_factory=connection_factory, async=async) | ||
if cursor_factory is not None: | ||
conn.cursor_factory = cursor_factory | ||
|
||
return conn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
"""Implementation of the JSON adaptation objects | ||
This module exists to avoid a circular import problem: pyscopg2.extras depends | ||
on psycopg2.extension, so I can't create the default JSON typecasters in | ||
extensions importing register_json from extras. | ||
""" | ||
|
||
# psycopg/_json.py - Implementation of the JSON adaptation objects | ||
# | ||
# Copyright (C) 2012 Daniele Varrazzo <daniele.varrazzo@gmail.com> | ||
# | ||
# psycopg2 is free software: you can redistribute it and/or modify it | ||
# under the terms of the GNU Lesser General Public License as published | ||
# by the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# In addition, as a special exception, the copyright holders give | ||
# permission to link this program with the OpenSSL library (or with | ||
# modified versions of OpenSSL that use the same license as OpenSSL), | ||
# and distribute linked combinations including the two. | ||
# | ||
# You must obey the GNU Lesser General Public License in all respects for | ||
# all of the code used other than OpenSSL. | ||
# | ||
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT | ||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
# License for more details. | ||
|
||
import sys | ||
|
||
from psycopg2._psycopg import ISQLQuote, QuotedString | ||
from psycopg2._psycopg import new_type, new_array_type, register_type | ||
|
||
|
||
# import the best json implementation available | ||
if sys.version_info[:2] >= (2,6): | ||
import json | ||
else: | ||
try: | ||
import simplejson as json | ||
except ImportError: | ||
json = None | ||
|
||
|
||
# oids from PostgreSQL 9.2 | ||
JSON_OID = 114 | ||
JSONARRAY_OID = 199 | ||
|
||
class Json(object): | ||
""" | ||
An `~psycopg2.extensions.ISQLQuote` wrapper to adapt a Python object to | ||
:sql:`json` data type. | ||
`!Json` can be used to wrap any object supported by the provided *dumps* | ||
function. If none is provided, the standard :py:func:`json.dumps()` is | ||
used (`!simplejson` for Python < 2.6; | ||
`~psycopg2.extensions.ISQLQuote.getquoted()` will raise `!ImportError` if | ||
the module is not available). | ||
""" | ||
def __init__(self, adapted, dumps=None): | ||
self.adapted = adapted | ||
|
||
if dumps is not None: | ||
self._dumps = dumps | ||
elif json is not None: | ||
self._dumps = json.dumps | ||
else: | ||
self._dumps = None | ||
|
||
def __conform__(self, proto): | ||
if proto is ISQLQuote: | ||
return self | ||
|
||
def dumps(self, obj): | ||
"""Serialize *obj* in JSON format. | ||
The default is to call `!json.dumps()` or the *dumps* function | ||
provided in the constructor. You can override this method to create a | ||
customized JSON wrapper. | ||
""" | ||
dumps = self._dumps | ||
if dumps is not None: | ||
return dumps(obj) | ||
else: | ||
raise ImportError( | ||
"json module not available: " | ||
"you should provide a dumps function") | ||
|
||
def getquoted(self): | ||
s = self.dumps(self.adapted) | ||
return QuotedString(s).getquoted() | ||
|
||
|
||
def register_json(conn_or_curs=None, globally=False, loads=None, | ||
oid=None, array_oid=None): | ||
"""Create and register typecasters converting :sql:`json` type to Python objects. | ||
:param conn_or_curs: a connection or cursor used to find the :sql:`json` | ||
and :sql:`json[]` oids; the typecasters are registered in a scope | ||
limited to this object, unless *globally* is set to `!True`. It can be | ||
`!None` if the oids are provided | ||
:param globally: if `!False` register the typecasters only on | ||
*conn_or_curs*, otherwise register them globally | ||
:param loads: the function used to parse the data into a Python object. If | ||
`!None` use `!json.loads()`, where `!json` is the module chosen | ||
according to the Python version (see above) | ||
:param oid: the OID of the :sql:`json` type if known; If not, it will be | ||
queried on *conn_or_curs* | ||
:param array_oid: the OID of the :sql:`json[]` array type if known; | ||
if not, it will be queried on *conn_or_curs* | ||
The connection or cursor passed to the function will be used to query the | ||
database and look for the OID of the :sql:`json` type. No query is | ||
performed if *oid* and *array_oid* are provided. Raise | ||
`~psycopg2.ProgrammingError` if the type is not found. | ||
""" | ||
if oid is None: | ||
oid, array_oid = _get_json_oids(conn_or_curs) | ||
|
||
JSON, JSONARRAY = _create_json_typecasters(oid, array_oid, loads) | ||
|
||
register_type(JSON, not globally and conn_or_curs or None) | ||
|
||
if JSONARRAY is not None: | ||
register_type(JSONARRAY, not globally and conn_or_curs or None) | ||
|
||
return JSON, JSONARRAY | ||
|
||
def register_default_json(conn_or_curs=None, globally=False, loads=None): | ||
""" | ||
Create and register :sql:`json` typecasters for PostgreSQL 9.2 and following. | ||
Since PostgreSQL 9.2 :sql:`json` is a builtin type, hence its oid is known | ||
and fixed. This function allows specifying a customized *loads* function | ||
for the default :sql:`json` type without querying the database. | ||
All the parameters have the same meaning of `register_json()`. | ||
""" | ||
return register_json(conn_or_curs=conn_or_curs, globally=globally, | ||
loads=loads, oid=JSON_OID, array_oid=JSONARRAY_OID) | ||
|
||
def _create_json_typecasters(oid, array_oid, loads=None): | ||
"""Create typecasters for json data type.""" | ||
if loads is None: | ||
if json is None: | ||
raise ImportError("no json module available") | ||
else: | ||
loads = json.loads | ||
|
||
def typecast_json(s, cur): | ||
if s is None: | ||
return None | ||
return loads(s) | ||
|
||
JSON = new_type((oid, ), 'JSON', typecast_json) | ||
if array_oid is not None: | ||
JSONARRAY = new_array_type((array_oid, ), "JSONARRAY", JSON) | ||
else: | ||
JSONARRAY = None | ||
|
||
return JSON, JSONARRAY | ||
|
||
def _get_json_oids(conn_or_curs): | ||
# lazy imports | ||
from psycopg2.extensions import STATUS_IN_TRANSACTION | ||
from psycopg2.extras import _solve_conn_curs | ||
|
||
conn, curs = _solve_conn_curs(conn_or_curs) | ||
|
||
# Store the transaction status of the connection to revert it after use | ||
conn_status = conn.status | ||
|
||
# column typarray not available before PG 8.3 | ||
typarray = conn.server_version >= 80300 and "typarray" or "NULL" | ||
|
||
# get the oid for the hstore | ||
curs.execute( | ||
"SELECT t.oid, %s FROM pg_type t WHERE t.typname = 'json';" | ||
% typarray) | ||
r = curs.fetchone() | ||
|
||
# revert the status of the connection as before the command | ||
if (conn_status != STATUS_IN_TRANSACTION and not conn.autocommit): | ||
conn.rollback() | ||
|
||
if not r: | ||
raise conn.ProgrammingError("json data type not found") | ||
|
||
return r | ||
|
||
|
||
|
Binary file not shown.
Oops, something went wrong.