Change to URI based env var config

- Bump rev to 2.0.0 since this is backwards incompatible
- Update docs
- Update tests
- move from FOO_HOST, FOO_PORT, etc to PGSQL_FOO=URI
This commit is contained in:
Gavin M. Roy 2014-10-07 11:59:15 -04:00
parent 86043e2733
commit 836ec3f140
6 changed files with 43 additions and 94 deletions

View file

@ -26,8 +26,8 @@ Requirements
Example
-------
The following example sets the environment variables for connecting to
PostgreSQL on localhost to the ``postgres`` database and issues a query.
The following example sets the environment variable for connecting to
PostgreSQL on localhost to the ``production`` database and issues a query.
.. code:: python
@ -35,12 +35,9 @@ PostgreSQL on localhost to the ``postgres`` database and issues a query.
from sprockets.clients import postgresql
os.environ['POSTGRES_HOST'] = 'localhost'
os.environ['POSTGRES_USER'] = 'postgres'
os.environ['POSTGRES_PORT'] = 5432
os.environ['POSTGRES_DBNAME'] = 'postgres'
os.environ['PGSQL_PROD'] = 'postgresql://postgres@localhost:5432/production'
session = postgresql.Session('postgres')
session = postgresql.Session('prod')
result = session.query('SELECT 1')
print(repr(result))

View file

@ -9,12 +9,9 @@ PostgreSQL on localhost to the ``postgres`` database and issues a query.
from sprockets.clients import postgresql
os.environ['POSTGRES_HOST'] = 'localhost'
os.environ['POSTGRES_USER'] = 'postgres'
os.environ['POSTGRES_PORT'] = 5432
os.environ['POSTGRES_DBNAME'] = 'postgres'
os.environ['PGSQL'] = 'postgresql://postgres@localhost:5432/postgres'
session = postgresql.Session('postgres')
session = postgresql.Session()
result = session.query('SELECT 1')
print(repr(result))
@ -30,15 +27,12 @@ class in a Tornado :py:class:`RequestHandler <tornado.web.RequestHandler>`.
from sprockets.clients import postgresql
from tornado import web
os.environ['POSTGRES_HOST'] = 'localhost'
os.environ['POSTGRES_USER'] = 'postgres'
os.environ['POSTGRES_PORT'] = 5432
os.environ['POSTGRES_DBNAME'] = 'postgres'
os.environ['PGSQL_FOO'] = 'postgresql://postgres@localhost:5432/foo'
class RequestHandler(web.RequestHandler):
def initialize(self):
self.session = postgresql.TornadoSession('postgres')
self.session = postgresql.TornadoSession('foo')
@gen.coroutine
def get(self, *args, **kwargs):

View file

@ -1,5 +1,7 @@
Version History
---------------
- 2.0.0 [2014-10-07]
- Change the environment variable format to be URI based instead of a variable per host, port, dbname, etc.
- 1.0.1 [2014-09-05]
- Expose psycopg2/queries exceptions, objects, etc from ``sprockets.queries.postgresql``
- Add integration testing with PostgreSQL

View file

@ -4,7 +4,7 @@ import setuptools
setuptools.setup(
name='sprockets.clients.postgresql',
version='1.0.1',
version='2.0.0',
description=('PostgreSQL client library wrapper providing environment '
'variable based configuration'),
long_description=codecs.open('README.rst', encoding='utf-8').read(),

View file

@ -5,19 +5,18 @@ The Session classes wrap the Queries :py:class:`Session <queries.Session>` and
:py:class:`TornadoSession <queries.tornado_session.TornadoSession>` classes
providing environment variable based configuration.
The environment variables should be set using the ``DBNAME_[VARIABLE]`` format
where ``[VARIABLE]`` is one of ``HOST``, ``PORT``, ``DBNAME``, ``USER``, and
``PASSWORD``.
Environment variables should be set using the ``PGSQL[_DBNAME]`` format
where the value is a PostgreSQL URI.
For example, given the environment variables:
For PostgreSQL URI format, see:
http://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNSTRING
As example, given the environment variable:
.. code:: python
FOO_HOST = 'foodb'
FOO_PORT = '6000'
FOO_DBNAME = 'foo'
FOO_USER = 'bar'
FOO_PASSWORD = 'baz'
PGSQL_FOO = 'postgresql://bar:baz@foohost:6000/foo'
and code for creating a :py:class:`Session` instance for the database name
``foo``:
@ -26,11 +25,12 @@ and code for creating a :py:class:`Session` instance for the database name
session = sprockets.postgresql.Session('foo')
The uri ``postgresql://bar:baz@foodb:6000/foo`` will be used when creating the
instance of :py:class:`queries.Session`.
A :py:class:`queries.Session` object will be created that connects to Postgres
running on ``foohost``, port ``6000`` using the username ``bar`` and the
password ``baz``, connecting to the ``foo`` database.
"""
version_info = (1, 0, 1)
version_info = (2, 0, 0)
__version__ = '.'.join(str(v) for v in version_info)
import logging
@ -66,27 +66,21 @@ from queries import TransactionRollbackError
def _get_uri(dbname):
"""Construct the URI for connecting to PostgreSQL by appending each
argument name to the dbname, delimited by an underscore and
capitalizing the new variable name.
Values will be retrieved from the environment variable and added to a
dictionary that is then passed in as keyword arguments to the
:py:meth:`queries.uri` method to build the URI string.
"""Return the URI for the specified database name from an environment
variable. If dbname is blank, the ``PGSQL`` environment variable is used,
otherwise the database name is cast to upper case and concatenated to
``PGSQL_`` and the URI is retrieved from ``PGSQL_DBNAME``. For example,
if the value ``foo`` is passed in, the environment variable used would be
``PGSQL_FOO``.
:param str dbname: The database name to construct the URI for
:return: str
:raises: KeyError
"""
kwargs = dict()
for arg in _ARGUMENTS:
value = os.getenv(('%s_%s' % (dbname, arg)).upper())
if value:
if arg == 'port':
kwargs[arg] = int(value)
else:
kwargs[arg] = value
return queries.uri(**kwargs)
if not dbname:
return os.environ['PGSQL']
return os.environ['PGSQL_{0}'.format(dbname).upper()]
class Session(queries.Session):

View file

@ -10,7 +10,6 @@ try:
except ImportError:
import unittest
from tornado import gen
from sprockets.clients import postgresql
import queries
from tornado import testing
@ -18,17 +17,9 @@ from tornado import testing
class TestGetURI(unittest.TestCase):
def tearDown(self):
for key in ['HOST', 'PORT', 'DBNAME', 'USER', 'PASSWORD']:
del os.environ['TEST1_%s' % key]
def test_get_uri_returns_proper_values(self):
os.environ['TEST1_HOST'] = 'test1-host'
os.environ['TEST1_PORT'] = '5436'
os.environ['TEST1_DBNAME'] = 'test1'
os.environ['TEST1_USER'] = 'foo1'
os.environ['TEST1_PASSWORD'] = 'baz1'
os.environ['PGSQL_TEST1'] = \
'postgresql://foo1:baz1@test1-host:5436/test1'
self.assertEqual(postgresql._get_uri('test1'),
'postgresql://foo1:baz1@test1-host:5436/test1')
@ -39,17 +30,9 @@ class TestSession(unittest.TestCase):
@mock.patch('queries.session.Session.__init__')
def setUp(self, mock_init):
self.mock_init = mock_init
os.environ['TEST2_HOST'] = 'db1'
os.environ['TEST2_PORT'] = '5433'
os.environ['TEST2_DBNAME'] = 'bar'
os.environ['TEST2_USER'] = 'foo'
os.environ['TEST2_PASSWORD'] = 'baz'
os.environ['PGSQL_TEST2'] = 'postgresql://foo:baz@db1:5433/bar'
self.session = postgresql.Session('test2')
def tearDown(self):
for key in ['HOST', 'PORT', 'DBNAME', 'USER', 'PASSWORD']:
del os.environ['TEST2_%s' % key]
def test_session_invokes_queries_session(self):
self.assertTrue(self.mock_init.called)
@ -59,17 +42,9 @@ class TestTornadoSession(unittest.TestCase):
@mock.patch('queries.tornado_session.TornadoSession.__init__')
def setUp(self, mock_init):
self.mock_init = mock_init
os.environ['TEST3_HOST'] = 'db1'
os.environ['TEST3_PORT'] = '5434'
os.environ['TEST3_DBNAME'] = 'bar'
os.environ['TEST3_USER'] = 'foo'
os.environ['TEST3_PASSWORD'] = 'baz'
os.environ['PGSQL_TEST3'] = 'postgresql://foo:baz@db1:5434/bar'
self.session = postgresql.TornadoSession('test3')
def tearDown(self):
for key in ['HOST', 'PORT', 'DBNAME', 'USER', 'PASSWORD']:
del os.environ['TEST3_%s' % key]
def test_session_invokes_queries_session(self):
self.assertTrue(self.mock_init.called)
@ -77,20 +52,13 @@ class TestTornadoSession(unittest.TestCase):
class SessionIntegrationTests(unittest.TestCase):
def setUp(self):
os.environ['TEST4_HOST'] = 'localhost'
os.environ['TEST4_PORT'] = '5432'
os.environ['TEST4_DBNAME'] = 'postgres'
os.environ['TEST4_USER'] = 'postgres'
os.environ['PGSQL_TEST4'] = \
'postgresql://postgres@localhost:5432/postgres'
try:
self.session = postgresql.Session('test', pool_max_size=10)
self.session = postgresql.Session('test4', pool_max_size=10)
except postgresql.OperationalError as error:
raise unittest.SkipTest(str(error).split('\n')[0])
def tearDown(self):
for key in ['HOST', 'PORT', 'DBNAME', 'USER']:
del os.environ['TEST4_%s' % key]
def test_query_returns_results_object(self):
self.assertIsInstance(self.session.query('SELECT 1 AS value'),
queries.Results)
@ -118,18 +86,12 @@ class TornadoSessionIntegrationTests(testing.AsyncTestCase):
def setUp(self):
super(TornadoSessionIntegrationTests, self).setUp()
os.environ['TEST5_HOST'] = 'localhost'
os.environ['TEST5_PORT'] = '5432'
os.environ['TEST5_DBNAME'] = 'postgres'
os.environ['TEST5_USER'] = 'postgres'
self.session = postgresql.TornadoSession('test',
os.environ['PGSQL_TEST5'] = \
'postgresql://postgres@localhost:5432/postgres'
self.session = postgresql.TornadoSession('test5',
pool_max_size=10,
io_loop=self.io_loop)
#def tearDown(self):
# for key in ['HOST', 'PORT', 'DBNAME', 'USER']:
# del os.environ['TEST5_%s' % key]
@testing.gen_test
def test_query_returns_results_object(self):
try: