Skip to content

Commit 23db75d

Browse files
adamhadanimwatts15
authored andcommitted
support connection options as dictionary
removed unused test.py, add unit-test for specifying configuration dict
1 parent 40db0b6 commit 23db75d

File tree

4 files changed

+52
-71
lines changed

4 files changed

+52
-71
lines changed

rdflib_sqlalchemy/store.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ def __init__(self, identifier=None, configuration=None, engine=None):
8484
8585
Args:
8686
identifier (rdflib.URIRef): URIRef of the Store. Defaults to CWD.
87-
engine (sqlalchemy.engine.Engine, optional): a `SQLAlchemy.engine.Engine` instance
87+
configuration: the database connection URL string or a configuration dictionary
88+
corresponding to the connection options accepted by sqlalchemy.create_engine,
89+
with the additional "url" key pointing to the connection URL. See `open` documentation
90+
for more details.
91+
engine (sqlalchemy.engine.Engine, optional): a pre-existing `SQLAlchemy.engine.Engine` instance.
8892
8993
"""
9094
self.identifier = identifier and identifier or "hardcoded"
@@ -214,9 +218,14 @@ def node_pickler(self):
214218

215219
def open(self, configuration, create=True):
216220
"""
217-
Open the store specified by the configuration string.
221+
Open the store specified by the configuration parameter.
218222
219223
Args:
224+
configuration: if a string, use as the DBAPI URL. If a dictionary, will use as the **kwargs
225+
for the sqlalchemy.create_engine() call, and will attempt to extract the connection URL
226+
from a 'url' key in that dictionary.
227+
A valid connection string will be of the format:
228+
dialect[+driver]://user:password@host/dbname[?key=value..]
220229
create (bool): If create is True a store will be created if it does not already
221230
exist. If create is False and a store does not already exist
222231
an exception is raised. An exception is also raised if a store
@@ -232,7 +241,14 @@ def open(self, configuration, create=True):
232241
# Close any existing engine connection
233242
self.close()
234243

235-
self.engine = sqlalchemy.create_engine(configuration)
244+
url, kwargs = configuration, {}
245+
if isinstance(configuration, dict):
246+
url = configuration.pop("url", None)
247+
if not url:
248+
raise Exception('Configuration dict is missing the required "url" key')
249+
kwargs = configuration
250+
251+
self.engine = sqlalchemy.create_engine(url, **kwargs)
236252
with self.engine.connect():
237253
if create:
238254
self.create_all()

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ description-file = README.md
44
[nosetests]
55
attr = !known_issue,!performancetest
66
verbosity = 2
7+
where = test
78

89
[flake8]
910
max-line-length = 120

test/test.py

Lines changed: 0 additions & 53 deletions
This file was deleted.

test/test_sqlalchemy.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,50 @@
1-
import logging
21
import unittest
2+
from unittest.mock import patch
33

44
from rdflib import (
55
ConjunctiveGraph,
66
Literal,
77
URIRef,
8+
plugin
89
)
9-
from rdflib import plugin
1010
from rdflib.store import Store
1111

1212
from rdflib_sqlalchemy import registerplugins
1313

1414

15-
_logger = logging.getLogger(__name__)
16-
1715
michel = URIRef(u"michel")
18-
tarek = URIRef(u"tarek")
19-
bob = URIRef(u"bob")
2016
likes = URIRef(u"likes")
21-
hates = URIRef(u"hates")
2217
pizza = URIRef(u"pizza")
23-
cheese = URIRef(u"cheese")
2418

2519

2620
class mock_cursor():
2721
def execute(x):
2822
raise Exception("Forced exception")
2923

3024

25+
class ConfigTest(unittest.TestCase):
26+
'''
27+
Test configuration with a dict
28+
'''
29+
30+
def setUp(self):
31+
self.store = plugin.get("SQLAlchemy", Store)()
32+
self.graph = ConjunctiveGraph(self.store)
33+
34+
def tearDown(self):
35+
self.graph.close()
36+
37+
def test_success(self):
38+
with patch('rdflib_sqlalchemy.store.sqlalchemy') as p:
39+
self.graph.open({'url': 'sqlite://', 'random_key': 'something'}, create=True)
40+
p.create_engine.assert_called_with('sqlite://', random_key='something')
41+
42+
def test_no_url(self):
43+
with patch('rdflib_sqlalchemy.store.sqlalchemy') as p:
44+
with self.assertRaisesRegex(Exception, '.*url.*'):
45+
self.graph.open({'random_key': 'something'}, create=True)
46+
47+
3148
class SQLATestCase(unittest.TestCase):
3249
identifier = URIRef("rdflib_test")
3350
dburi = Literal("sqlite://")
@@ -46,26 +63,26 @@ def test_registerplugins(self):
4663
# I doubt this is quite right for a fresh pip installation,
4764
# this test is mainly here to fill a coverage gap.
4865
registerplugins()
49-
self.assert_(plugin.get("SQLAlchemy", Store) is not None)
66+
self.assertIsNotNone(plugin.get("SQLAlchemy", Store))
5067
p = plugin._plugins
51-
self.assert_(("SQLAlchemy", Store) in p, p)
68+
self.assertIn(("SQLAlchemy", Store), p)
5269
del p[("SQLAlchemy", Store)]
5370
plugin._plugins = p
5471
registerplugins()
55-
self.assert_(("SQLAlchemy", Store) in p, p)
72+
self.assertIn(("SQLAlchemy", Store), p)
5673

5774
def test_namespaces(self):
58-
self.assert_(list(self.graph.namespaces()) != [])
75+
self.assertNotEqual(list(self.graph.namespaces()), [])
5976

6077
def test_contexts_without_triple(self):
61-
self.assert_(list(self.graph.contexts()) == [])
78+
self.assertEqual(list(self.graph.contexts()), [])
6279

6380
def test_contexts_with_triple(self):
6481
statemnt = (michel, likes, pizza)
65-
self.assert_(self.graph.contexts(triple=statemnt) != [])
82+
self.assertEqual(list(self.graph.contexts(triple=statemnt)), [])
6683

6784
def test__len(self):
68-
self.assert_(self.store.__len__() == 0)
85+
self.assertEqual(self.store.__len__(), 0)
6986

7087
def test__remove_context(self):
7188
self.store._remove_context(self.identifier)

0 commit comments

Comments
 (0)