Skip to content

Commit 0db2f2f

Browse files
authoredSep 3, 2021
Merge pull request #40 from maxxiefjv/feature/allow-redis-tls
Feature request: allow extra options for storage backends
2 parents 2f110dc + 04fee31 commit 0db2f2f

File tree

2 files changed

+53
-30
lines changed

2 files changed

+53
-30
lines changed
 

‎src/pyop/storage.py

+35-11
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,23 @@ def pop(self, key, default=None):
5252
return data
5353

5454
@classmethod
55-
def from_uri(cls, db_uri, collection, db_name=None, ttl=None):
55+
def from_uri(cls, db_uri, collection, db_name=None, ttl=None, **kwargs):
5656
if db_uri.startswith("mongodb"):
5757
return MongoWrapper(
58-
db_uri=db_uri, db_name=db_name, collection=collection, ttl=ttl
58+
db_uri=db_uri,
59+
db_name=db_name,
60+
collection=collection,
61+
ttl=ttl,
62+
extra_options=kwargs,
5963
)
6064
elif db_uri.startswith("redis") or db_uri.startswith("unix"):
61-
return RedisWrapper(db_uri=db_uri, collection=collection, ttl=ttl)
65+
return RedisWrapper(
66+
db_uri=db_uri,
67+
db_name=db_name,
68+
collection=collection,
69+
ttl=ttl,
70+
extra_options=kwargs,
71+
)
6272

6373
return ValueError(f"Invalid DB URI: {db_uri}")
6474

@@ -68,12 +78,18 @@ def ttl(self):
6878

6979

7080
class MongoWrapper(StorageBase):
71-
def __init__(self, db_uri, db_name, collection, ttl=None):
81+
def __init__(self, db_uri, db_name, collection, ttl=None, extra_options=None):
7282
if not _has_pymongo:
7383
raise ImportError("pymongo module is required but it is not available")
84+
85+
if not extra_options:
86+
extra_options = {}
87+
88+
mongo_options = extra_options.pop("mongo_kwargs", None) or {}
89+
7490
self._db_uri = db_uri
7591
self._coll_name = collection
76-
self._db = MongoDB(db_uri, db_name=db_name)
92+
self._db = MongoDB(db_uri, db_name=db_name, **mongo_options)
7793
self._coll = self._db.get_collection(collection)
7894
self._coll.create_index('lookup_key', unique=True)
7995

@@ -120,10 +136,21 @@ class RedisWrapper(StorageBase):
120136
Supports JSON-serializable data types.
121137
"""
122138

123-
def __init__(self, db_uri, collection, ttl=None):
139+
def __init__(
140+
self, db_uri, *, db_name=None, collection, ttl=None, extra_options=None
141+
):
124142
if not _has_redis:
125143
raise ImportError("redis module is required but it is not available")
126-
self._db = Redis.from_url(db_uri, decode_responses=True)
144+
145+
if not extra_options:
146+
extra_options = {}
147+
148+
redis_kwargs = extra_options.pop("redis_kwargs", None) or {}
149+
redis_options = {
150+
"decode_responses": True, "db": db_name, **redis_kwargs
151+
}
152+
153+
self._db = Redis.from_url(db_uri, **redis_options)
127154
self._collection = collection
128155
if ttl is None or (isinstance(ttl, int) and ttl >= 0):
129156
self._ttl = ttl
@@ -170,14 +197,11 @@ def items(self):
170197
class MongoDB(object):
171198
"""Simple wrapper to get pymongo real objects from the settings uri"""
172199

173-
def __init__(self, db_uri, db_name=None,
174-
connection_factory=None, **kwargs):
175-
200+
def __init__(self, db_uri, db_name=None, connection_factory=None, **kwargs):
176201
if db_uri is None:
177202
raise ValueError('db_uri not supplied')
178203

179204
self._sanitized_uri = None
180-
181205
self._parsed_uri = pymongo.uri_parser.parse_uri(db_uri)
182206

183207
db_name = self._parsed_uri.get('database') or db_name

‎tests/pyop/test_storage.py

+18-19
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616
__author__ = 'lundberg'
1717

1818

19-
uri_list = ["mongodb://localhost:1234/pyop", "redis://localhost/0"]
19+
db_specs_list = [
20+
{"uri": "mongodb://localhost:1234/pyop", "name": "pyop"},
21+
{"uri": "redis://localhost/0", "name": 0},
22+
]
23+
2024

2125
@pytest.fixture(autouse=True)
2226
def mock_redis(monkeypatch):
2327
def mockreturn(*args, **kwargs):
24-
return fakeredis.FakeStrictRedis(decode_responses=True)
28+
return fakeredis.FakeStrictRedis(*args, **kwargs)
2529
monkeypatch.setattr(Redis, "from_url", mockreturn)
2630

2731
@pytest.fixture(autouse=True)
@@ -30,10 +34,10 @@ def mock_mongo():
3034

3135

3236
class TestStorage(object):
33-
@pytest.fixture(params=uri_list)
37+
@pytest.fixture(params=db_specs_list)
3438
def db(self, request):
3539
return pyop.storage.StorageBase.from_uri(
36-
request.param, db_name="pyop", collection="test"
40+
request.param["uri"], db_name=request.param["name"], collection="test"
3741
)
3842

3943
def test_write(self, db):
@@ -69,15 +73,15 @@ def test_items(self, db):
6973
@pytest.mark.parametrize(
7074
"args,kwargs",
7175
[
72-
(["redis://localhost"], {"collection": "test"}),
73-
(["redis://localhost", "test"], {}),
74-
(["unix://localhost/0"], {"collection": "test", "ttl": 3}),
7576
(["mongodb://localhost/pyop"], {"collection": "test", "ttl": 3}),
7677
(["mongodb://localhost"], {"db_name": "pyop", "collection": "test"}),
7778
(["mongodb://localhost", "test", "pyop"], {}),
7879
(["mongodb://localhost/pyop", "test"], {}),
7980
(["mongodb://localhost/pyop"], {"db_name": "other", "collection": "test"}),
80-
(["redis://localhost/0"], {"db_name": "pyop", "collection": "test"}),
81+
(["redis://localhost"], {"collection": "test"}),
82+
(["redis://localhost", "test"], {}),
83+
(["redis://localhost"], {"db_name": 2, "collection": "test"}),
84+
(["unix://localhost/0"], {"collection": "test", "ttl": 3}),
8185
],
8286
)
8387
def test_from_uri(self, args, kwargs):
@@ -88,11 +92,7 @@ def test_from_uri(self, args, kwargs):
8892
@pytest.mark.parametrize(
8993
"error,args,kwargs",
9094
[
91-
(
92-
TypeError,
93-
["redis://localhost", "ouch"],
94-
{"db_name": 3, "collection": "test", "ttl": None},
95-
),
95+
(ValueError, ["mongodb://localhost"], {"collection": "test", "ttl": None}),
9696
(
9797
TypeError,
9898
["mongodb://localhost", "ouch"],
@@ -110,12 +110,11 @@ def test_from_uri(self, args, kwargs):
110110
),
111111
(
112112
TypeError,
113-
["mongodb://localhost"],
114-
{"db_name": "pyop", "collection": "test", "ttl": None, "extra": True},
113+
["redis://localhost", "ouch"],
114+
{"db_name": 3, "collection": "test", "ttl": None},
115115
),
116116
(TypeError, ["redis://localhost/0"], {}),
117117
(TypeError, ["redis://localhost/0"], {"db_name": "pyop"}),
118-
(ValueError, ["mongodb://localhost"], {"collection": "test", "ttl": None}),
119118
],
120119
)
121120
def test_from_uri_invalid_parameters(self, error, args, kwargs):
@@ -153,11 +152,11 @@ def execute_ttl_test(self, uri, ttl):
153152
with pytest.raises(KeyError):
154153
self.db["foo"]
155154

156-
@pytest.mark.parametrize("uri", uri_list)
155+
@pytest.mark.parametrize("spec", db_specs_list)
157156
@pytest.mark.parametrize("ttl", ["invalid", -1, 2.3, {}])
158-
def test_invalid_ttl(self, uri, ttl):
157+
def test_invalid_ttl(self, spec, ttl):
159158
with pytest.raises(ValueError):
160-
self.prepare_db(uri, ttl)
159+
self.prepare_db(spec["uri"], ttl)
161160

162161

163162
class TestRedisTTL(StorageTTLTest):

0 commit comments

Comments
 (0)
Please sign in to comment.