Skip to content

Commit f67ee73

Browse files
author
Brendan W. McAdams
committed
- Updated URI Parser to support options (only slaveok can be set at the moment) per http://www.mongodb.org/display/DOCS/Connections
- Added support for <db>.<collection> namespace in URI as the java driver supports
1 parent 9ee7242 commit f67ee73

File tree

2 files changed

+68
-18
lines changed

2 files changed

+68
-18
lines changed

pymongo/connection.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,28 @@ def _str_to_node(string, default_port=27017):
8181
return (host, port)
8282

8383

84-
def _parse_uri(uri, default_port):
84+
def _parse_uri(uri, default_port=27017):
8585
"""MongoDB URI parser.
8686
"""
87-
info = {}
8887

8988
if uri.startswith("mongodb://"):
9089
uri = uri[len("mongodb://"):]
9190
elif "://" in uri:
9291
raise InvalidURI("Invalid uri scheme: %s" % _partition(uri, "://")[0])
9392

94-
(hosts, database) = _partition(uri, "/")
93+
(hosts, namespace) = _partition(uri, "/")
9594

96-
if not database:
97-
database = None
95+
raw_options = None
96+
if namespace:
97+
(namespace, raw_options) = _partition(namespace, "?")
98+
if namespace.find(".") < 0:
99+
db = namespace
100+
collection = None
101+
else:
102+
(db, collection) = namespace.split(".", 1)
103+
else:
104+
db = None
105+
collection = None
98106

99107
username = None
100108
password = None
@@ -112,7 +120,21 @@ def _parse_uri(uri, default_port):
112120
raise InvalidURI("empty host (or extra comma in host list)")
113121
host_list.append(_str_to_node(host, default_port))
114122

115-
return (host_list, database, username, password)
123+
options = {}
124+
if raw_options:
125+
and_idx = raw_options.find("&")
126+
semi_idx = raw_options.find(";")
127+
if and_idx >= 0 and semi_idx >= 0:
128+
raise InvalidURI("Cannot mix & and ; for option separators.")
129+
elif and_idx >= 0:
130+
options = dict([kv.split("=") for kv in raw_options.split("&")])
131+
elif semi_idx >= 0:
132+
options = dict([kv.split("=") for kv in raw_options.split(";")])
133+
elif raw_options.find("="):
134+
options = dict([raw_options.split("=")])
135+
136+
137+
return (host_list, db, username, password, collection, options)
116138

117139

118140
def _closed(sock):
@@ -266,12 +288,16 @@ def __init__(self, host=None, port=None, pool_size=None,
266288
database = None
267289
username = None
268290
password = None
291+
collection = None
292+
options = {}
269293
for uri in host:
270-
(n, db, u, p) = _parse_uri(uri, port)
294+
(n, db, u, p, coll, opts) = _parse_uri(uri, port)
271295
nodes.update(n)
272296
database = db or database
273297
username = u or username
274298
password = p or password
299+
collection = coll or collection
300+
options = opts or options
275301
if not nodes:
276302
raise ConfigurationError("need to specify at least one host")
277303
self.__nodes = nodes
@@ -292,11 +318,20 @@ def __init__(self, host=None, port=None, pool_size=None,
292318
self.__host = None
293319
self.__port = None
294320

295-
self.__slave_okay = slave_okay
321+
if options.has_key("slaveok"):
322+
self.__slave_okay = options['slaveok'][0].upper()=='T'
323+
else:
324+
self.__slave_okay = slave_okay
325+
296326
if slave_okay and len(self.__nodes) > 1:
297327
raise ConfigurationError("cannot specify slave_okay for a paired "
298328
"or replica set connection")
299329

330+
# TODO - Support using other options like w and fsync from URI
331+
self.__options = options
332+
# TODO - Support setting the collection from URI as the Java driver does
333+
self.__collection = collection
334+
300335
self.__cursor_manager = CursorManager(self)
301336

302337
self.__pool = _Pool(self.__connect)

test/test_connection.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,40 +236,53 @@ def test_disconnect(self):
236236
coll.count()
237237

238238
def test_parse_uri(self):
239-
self.assertEqual(([("localhost", 27017)], None, None, None),
239+
self.assertEqual(([("localhost", 27017)], None, None, None, None, {}),
240240
_parse_uri("localhost", 27017))
241-
self.assertEqual(([("localhost", 27018)], None, None, None),
241+
self.assertEqual(([("localhost", 27018)], None, None, None, None, {}),
242242
_parse_uri("localhost", 27018))
243243
self.assertRaises(InvalidURI, _parse_uri,
244244
"http://foobar.com", 27017)
245245
self.assertRaises(InvalidURI, _parse_uri,
246246
"http://[email protected]", 27017)
247247

248-
self.assertEqual(([("localhost", 27017)], None, None, None),
248+
self.assertEqual(([("localhost", 27017)], None, None, None, None, {}),
249249
_parse_uri("mongodb://localhost", 27017))
250-
self.assertEqual(([("localhost", 27017)], None, "fred", "foobar"),
250+
self.assertEqual(([("localhost", 27017)], None, "fred", "foobar", None, {}),
251251
_parse_uri("mongodb://fred:foobar@localhost",
252252
27017))
253-
self.assertEqual(([("localhost", 27017)], "baz", "fred", "foobar"),
253+
self.assertEqual(([("localhost", 27017)], "baz", "fred", "foobar", None, {}),
254254
_parse_uri("mongodb://fred:foobar@localhost/baz",
255255
27017))
256256
self.assertEqual(([("example1.com", 27017), ("example2.com", 27017)],
257-
None, None, None),
257+
None, None, None, None, {}),
258258
_parse_uri("mongodb://example1.com:27017,example2.com:27017",
259259
27018))
260260
self.assertEqual(([("localhost", 27017),
261261
("localhost", 27018),
262-
("localhost", 27019)], None, None, None),
262+
("localhost", 27019)], None, None, None, None, {}),
263263
_parse_uri("mongodb://localhost,localhost:27018,localhost:27019",
264264
27017))
265265

266-
self.assertEqual(([("localhost", 27018)], None, None, None),
266+
self.assertEqual(([("localhost", 27018)], None, None, None, None, {}),
267267
_parse_uri("localhost:27018", 27017))
268-
self.assertEqual(([("localhost", 27017)], "foo", None, None),
268+
self.assertEqual(([("localhost", 27017)], "foo", None, None, None, {}),
269269
_parse_uri("localhost/foo", 27017))
270-
self.assertEqual(([("localhost", 27017)], None, None, None),
270+
self.assertEqual(([("localhost", 27017)], None, None, None, None, {}),
271271
_parse_uri("localhost/", 27017))
272272

273+
self.assertEqual(([("localhost", 27017)], "test", None, None, "yield_historical.in", {}),
274+
_parse_uri("mongodb://localhost/test.yield_historical.in", 27017))
275+
self.assertEqual(([("localhost", 27017)], "test", "fred", "foobar", "yield_historical.in", {}),
276+
_parse_uri("mongodb://fred:foobar@localhost/test.yield_historical.in",
277+
27017))
278+
self.assertEqual(([("example1.com", 27017), ("example2.com", 27017)],
279+
"test", None, None, "yield_historical.in", {}),
280+
_parse_uri("mongodb://example1.com:27017,example2.com:27017/test.yield_historical.in",
281+
27017))
282+
self.assertEqual(([("localhost", 27017)], "test", "fred", "foobar", "yield_historical.in", {'slaveok': 'true'}),
283+
_parse_uri("mongodb://fred:foobar@localhost/test.yield_historical.in?slaveok=true",
284+
27017))
285+
273286
def test_from_uri(self):
274287
c = Connection(self.host, self.port)
275288

@@ -304,6 +317,8 @@ def test_from_uri(self):
304317
self.assert_(Connection("mongodb://%s:%s" %
305318
(self.host, self.port),
306319
slave_okay=True).slave_okay)
320+
self.assert_(Connection("mongodb://%s:%s/?slaveok=true;w=2" %
321+
(self.host, self.port)).slave_okay)
307322

308323
def test_fork(self):
309324
"""Test using a connection before and after a fork.

0 commit comments

Comments
 (0)