Skip to content
This repository has been archived by the owner on Sep 24, 2022. It is now read-only.

Commit

Permalink
Added API documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
FSX committed Dec 28, 2012
1 parent 4f1f404 commit d1a30b9
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Momoko
======

A Tornado_ wrapper for Psycopg2_.
Wraps (asynchronous) Psycopg2_ for Tornado_

.. _Psycopg2: http://www.initd.org/psycopg/
.. _Tornado: http://www.tornadoweb.org/
Expand Down
4 changes: 2 additions & 2 deletions changelog.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
News/Changelog
==============
Changelog
=========

1.0.0b1 (2012-12-16)
------------------
Expand Down
2 changes: 1 addition & 1 deletion momoko/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
momoko
======
Asynchronous Psycopg wrapper for Tornado.
Wraps (asynchronous) Psycopg2 for Tornado.
Copyright 2011-2012 by Frank Smit.
MIT, see LICENSE for more details.
Expand Down
222 changes: 207 additions & 15 deletions momoko/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,32 @@

# The dummy callback is used to keep the asynchronous cursor alive in case no
# callback has been specified. This will prevent the cursor from being garbage
# collected once, for example, ``ConnectionPool.execute`` has finished.
# collected once, for example, ``Pool.execute`` has finished.
def _dummy_callback(cursor, error):
pass


class Pool:
"""
Asynchronous connection pool.
The pool manages database connections and passes operations to connections.
See :py:class:`momoko.Connection` for documentation about the ``dsn`` and
``connection_factory`` parameters. These are used by the connection pool when
a new connection is created.
:param integer minconn: Amount of connections created upon initialization. Defaults to ``1``.
:param integer maxconn: Maximum amount of connections allowed by the pool. Defaults to ``5``.
:param integer cleanup_timeout:
Time in seconds between pool cleanups. Unused connections are closed and
removed from the pool until only ``minconn`` are left. When an integer
below ``1``, like ``-1`` is used the pool cleaner will be disabled.
Defaults to ``10``.
:param callable callback:
A callable that's called after all the connections are created. Defaults to ``None``.
:param ioloop: An instance of Tornado's IOLoop. Defaults to ``None``.
"""
def __init__(self,
dsn,
connection_factory=None,
Expand Down Expand Up @@ -73,6 +93,13 @@ def after_connect(_):
self._cleaner.start()

def new(self, callback=None):
"""
Create a new connection and add it to the pool.
:param callable callback:
A callable that's called after the connection is created. It accepts
one paramater: an instance of :py:class:`momoko.Connection`. Defaults to ``None``.
"""
if len(self._pool) > self.maxconn:
raise PoolError('connection pool exausted')

Expand Down Expand Up @@ -107,9 +134,15 @@ def _clean_pool(self):
def transaction(self,
statements,
cursor_factory=None,
callback=_dummy_callback,
callback=None,
connection=None
):
"""
Run a sequence of SQL queries in a database transaction.
See :py:meth:`momoko.Connection.transaction` for documentation about the
parameters. The ``connection`` parameter is for internal use.
"""
connection = connection or self._get_connection()
if not connection:
return self.new(lambda connection: self.transaction(
Expand All @@ -121,9 +154,15 @@ def execute(self,
operation,
parameters=(),
cursor_factory=None,
callback=_dummy_callback,
callback=None,
connection=None
):
"""
Prepare and execute a database operation (query or command).
See :py:meth:`momoko.Connection.execute` for documentation about the
parameters. The ``connection`` parameter is for internal use.
"""
connection = connection or self._get_connection()
if not connection:
return self.new(lambda connection: self.execute(operation,
Expand All @@ -135,9 +174,15 @@ def callproc(self,
procname,
parameters=(),
cursor_factory=None,
callback=_dummy_callback,
callback=None,
connection=None
):
"""
Call a stored database procedure with the given name.
See :py:meth:`momoko.Connection.callproc` for documentation about the
parameters. The ``connection`` parameter is for internal use.
"""
connection = connection or self._get_connection()
if not connection:
return self.new(lambda connection: self.callproc(procname,
Expand All @@ -148,9 +193,15 @@ def callproc(self,
def mogrify(self,
operation,
parameters=(),
callback=_dummy_callback,
callback=None,
connection=None
):
"""
Return a query string after arguments binding.
See :py:meth:`momoko.Connection.mogrify` for documentation about the
parameters. The ``connection`` parameter is for internal use.
"""
connection = connection or self._get_connection()
if not connection:
return self.new(lambda connection: self.mogrify(operation,
Expand All @@ -159,6 +210,9 @@ def mogrify(self,
connection.mogrify(operation, parameters, callback)

def close(self):
"""
Close the connection pool.
"""
if self.closed:
raise PoolError('connection pool is already closed')

Expand All @@ -173,6 +227,36 @@ def close(self):


class Connection:
"""
Create an asynchronous connection.
:param string dsn:
A `Data Source Name`_ string containing one of the following values:
* **dbname** - the database name
* **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)
Or any other parameter supported by PostgreSQL. See the PostgreSQL
documentation for a complete list of supported parameters_.
:param connection_factory:
The ``connection_factory`` argument can be used to create non-standard
connections. The class returned should be a subclass of `psycopg2.extensions.connection`_.
See `Connection and cursor factories`_ for details. Defaults to ``None``.
:param callable callback:
A callable that's called after the connection is created. It accepts one
paramater: an instance of :py:class:`momoko.Connection`. Defaults to ``None``.
:param ioloop: An instance of Tornado's IOLoop. Defaults to ``None``.
.. _Data Source Name: http://en.wikipedia.org/wiki/Data_Source_Name
.. _parameters: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS
.. _psycopg2.extensions.connection: http://initd.org/psycopg/docs/connection.html#connection
.. _Connection and cursor factories: http://initd.org/psycopg/docs/advanced.html#subclassing-cursor
"""
def __init__(self,
dsn,
connection_factory=None,
Expand Down Expand Up @@ -218,39 +302,139 @@ def execute(self,
operation,
parameters=(),
cursor_factory=None,
callback=_dummy_callback
callback=None
):
"""
Prepare and execute a database operation (query or command).
:param string operation: An SQL query.
:param tuple/list parameters:
A list or tuple with query parameters. See `Passing parameters to SQL queries`_
for more information. Defaults to an empty tuple.
:param cursor_factory:
The ``cursor_factory`` argument can be used to create non-standard cursors.
The class returned must be a subclass of `psycopg2.extensions.cursor`_.
See `Connection and cursor factories`_ for details. Defaults to ``None``.
:param callable callback:
A callable that is executed when the query has finished. It must accept
two positional parameters. The first one being the cursor and the second
one ``None`` or an instance of an exception if an error has occurred,
in that case the first parameter will be ``None``. Defaults to ``None``.
.. _Passing parameters to SQL queries: http://initd.org/psycopg/docs/usage.html#query-parameters
.. _psycopg2.extensions.cursor: http://initd.org/psycopg/docs/extensions.html#psycopg2.extensions.cursor
.. _Connection and cursor factories: http://initd.org/psycopg/docs/advanced.html#subclassing-cursor
"""
cursor = self.connection.cursor(cursor_factory=cursor_factory or base_cursor)
cursor.execute(operation, parameters)
self.callback = partial(callback, cursor)
self.callback = partial(callback or _dummy_callback, cursor)
self.ioloop.update_handler(self.fileno, IOLoop.WRITE)

def callproc(self,
procname,
parameters=(),
cursor_factory=None,
callback=_dummy_callback
callback=None
):
"""
Call a stored database procedure with the given name.
The sequence of parameters must contain one entry for each argument that
the procedure expects. The result of the call is returned as modified copy
of the input sequence. Input parameters are left untouched, output and
input/output parameters replaced with possibly new values.
The procedure may also provide a result set as output. This must then be
made available through the standard `fetch*()`_ methods.
:param string operation: The name of the database procedure.
:param tuple/list parameters:
A list or tuple with query parameters. See `Passing parameters to SQL queries`_
for more information. Defaults to an empty tuple.
:param cursor_factory:
The ``cursor_factory`` argument can be used to create non-standard cursors.
The class returned must be a subclass of `psycopg2.extensions.cursor`_.
See `Connection and cursor factories`_ for details. Defaults to ``None``.
:param callable callback:
A callable that is executed when the query has finished. It must accept
two positional parameters. The first one being the cursor and the second
one ``None`` or an instance of an exception if an error has occurred,
in that case the first parameter will be ``None``. Defaults to ``None``.
.. _fetch*(): http://initd.org/psycopg/docs/cursor.html#fetch
.. _Passing parameters to SQL queries: http://initd.org/psycopg/docs/usage.html#query-parameters
.. _psycopg2.extensions.cursor: http://initd.org/psycopg/docs/extensions.html#psycopg2.extensions.cursor
.. _Connection and cursor factories: http://initd.org/psycopg/docs/advanced.html#subclassing-cursor
"""
cursor = self.connection.cursor(cursor_factory=cursor_factory or base_cursor)
cursor.callproc(procname, parameters)
self.callback = partial(callback, cursor)
self.callback = partial(callback or _dummy_callback, cursor)
self.ioloop.update_handler(self.fileno, IOLoop.WRITE)

def mogrify(self, operation, parameters=(), callback=_dummy_callback):
def mogrify(self, operation, parameters=(), callback=None):
"""
Return a query string after arguments binding.
The string returned is exactly the one that would be sent to the database
running the execute() method or similar.
:param string operation: An SQL query.
:param tuple/list parameters:
A list or tuple with query parameters. See `Passing parameters to SQL queries`_
for more information. Defaults to an empty tuple.
:param callable callback:
A callable that is executed when the query has finished. It must accept
two positional parameters. The first one being the resulting query as
a byte string and the second one ``None`` or an instance of an exception
if an error has occurred. Defaults to ``None``.
.. _Passing parameters to SQL queries: http://initd.org/psycopg/docs/usage.html#query-parameters
.. _Connection and cursor factories: http://initd.org/psycopg/docs/advanced.html#subclassing-cursor
"""
cursor = self.connection.cursor()
try:
result = cursor.mogrify(operation, parameters)
self.ioloop.add_callback(partial(callback, result, None))
self.ioloop.add_callback(partial(callback or _dummy_callback, result, None))
except (psycopg2.Warning, psycopg2.Error) as error:
self.ioloop.add_callback(partial(callback, b'', error))
self.ioloop.add_callback(partial(callback or _dummy_callback, b'', error))

def transaction(self,
statements,
cursor_factory=None,
callback=_dummy_callback
callback=None
):
"""
Run a sequence of SQL queries in a database transaction.
:param tuple/list statements:
List or tuple containing SQL queries with or without parameters. An item
can be a string (SQL query without parameters) or a tuple/list with two items,
an SQL query and a tuple/list wuth parameters. An example::
(
'SELECT 1, 2, 3;', # Without parameters
('SELECT 4, %s, 6, %s;', (5, 7)), # With parameters
)
See `Passing parameters to SQL queries`_ for more information.
:param cursor_factory:
The ``cursor_factory`` argument can be used to create non-standard cursors.
The class returned must be a subclass of `psycopg2.extensions.cursor`_.
See `Connection and cursor factories`_ for details. Defaults to ``None``.
:param callable callback:
A callable that is executed when the transaction has finished. It must accept
two positional parameters. The first one being a list of cursors in the same
order as the given statements and the second one ``None`` or an instance of
an exception if an error has occurred, in that case the first parameter is
an empty list. Defaults to ``None``.
.. _Passing parameters to SQL queries: http://initd.org/psycopg/docs/usage.html#query-parameters
.. _psycopg2.extensions.cursor: http://initd.org/psycopg/docs/extensions.html#psycopg2.extensions.cursor
.. _Connection and cursor factories: http://initd.org/psycopg/docs/advanced.html#subclassing-cursor
"""
cursors = []
queue = deque()
callback = callback or _dummy_callback

for statement in statements:
if isinstance(statement, str):
Expand All @@ -263,8 +447,7 @@ def transaction(self,

def exec_statement(cursor=None, error=None):
if error:
self.execute('ROLLBACK;',
callback=partial(error_callback, error))
self.execute('ROLLBACK;', callback=partial(error_callback, error))
return
if cursor:
cursors.append(cursor)
Expand All @@ -281,14 +464,23 @@ def error_callback(statement_error, cursor, rollback_error):
self.ioloop.add_callback(exec_statement)

def busy(self):
"""
Check if the connection is busy or not.
"""
return self.connection.isexecuting() or (self.connection.closed == 0 and
self._transaction_status() != TRANSACTION_STATUS_IDLE)

@property
def closed(self):
"""
Indicates whether the connection is closed or not.
"""
# 0 = open, 1 = closed, 2 = 'something horrible happened'
return self.connection.closed > 0

def close(self):
"""
Remove the connection from the IO loop and close it.
"""
self.ioloop.remove_handler(self.fileno)
self.connection.close()
4 changes: 4 additions & 0 deletions momoko/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@


class PoolError(Exception):
"""
The ``PoolError`` exception is raised when something goes wrong in the connection
pool. When the maximum amount is exceeded for example.
"""
pass
4 changes: 2 additions & 2 deletions momoko/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ def set_up(self):
def tear_down(self):
pass


class MomokoTest(BaseTest):
def stop_callback(self, result, error):
self.stop((result, error))

Expand All @@ -59,6 +57,8 @@ def wait_for_result(self):
raise error
return cursor


class MomokoTest(BaseTest):
def clean_db(self):
self.db.execute('DROP TABLE IF EXISTS unit_test_large_query;',
callback=self.stop_callback)
Expand Down
Loading

0 comments on commit d1a30b9

Please sign in to comment.