Skip to content

Commit 0f4f593

Browse files
committed
BUG23550057: Add support for URI as connection data
This patch adds support for creating a Session object using an URI as connection data. A test case was added for regression.
1 parent 5b1279e commit 0f4f593

File tree

2 files changed

+123
-4
lines changed

2 files changed

+123
-4
lines changed

lib/mysqlx/__init__.py

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
"""MySQL X DevAPI Python implementation"""
2525

26+
from urlparse import urlparse
27+
2628
from .connection import XSession, NodeSession
2729
from .crud import Schema, Collection, Table
2830
from .errors import (Error, Warning, InterfaceError, DatabaseError,
@@ -39,27 +41,86 @@
3941
from .dbdoc import DbDoc
4042

4143

42-
def get_session(settings):
44+
def _get_connection_settings(*args, **kwargs):
45+
"""Parses the connection string and returns a dictionary with the
46+
connection settings.
47+
48+
Args:
49+
*args: Variable length argument list with the connection data used
50+
to connect to the database. It can be a dictionary or a
51+
connection string.
52+
**kwargs: Arbitrary keyword arguments with connection data used to
53+
connect to the database.
54+
55+
Returns:
56+
mysqlx.XSession: XSession object.
57+
"""
58+
settings = {}
59+
if args:
60+
if isinstance(args[0], (str, unicode,)):
61+
uri = "{0}{1}".format("" if args[0].startswith("mysqlx://")
62+
else "mysqlx://", args[0])
63+
parsed = urlparse(uri)
64+
if parsed.hostname is None or parsed.username is None \
65+
or parsed.password is None:
66+
raise InterfaceError("Malformed URI '{0}'".format(args[0]))
67+
settings = {
68+
"host": parsed.hostname,
69+
"port": parsed.port,
70+
"user": parsed.username,
71+
"password": parsed.password,
72+
"database": parsed.path.lstrip("/")
73+
}
74+
elif isinstance(args[0], dict):
75+
settings = args[0]
76+
elif kwargs:
77+
settings = kwargs
78+
79+
if not settings:
80+
raise InterfaceError("Settings not provided")
81+
82+
if "port" in settings and settings["port"]:
83+
try:
84+
settings["port"] = int(settings["port"])
85+
except NameError:
86+
raise InterfaceError("Invalid port")
87+
else:
88+
settings["port"] = 33060
89+
90+
return settings
91+
92+
93+
def get_session(*args, **kwargs):
4394
"""Creates a XSession instance using the provided connection data.
4495
4596
Args:
46-
settings (dict): Connection data used to connect to the database.
97+
*args: Variable length argument list with the connection data used
98+
to connect to the database. It can be a dictionary or a
99+
connection string.
100+
**kwargs: Arbitrary keyword arguments with connection data used to
101+
connect to the database.
47102
48103
Returns:
49104
mysqlx.XSession: XSession object.
50105
"""
106+
settings = _get_connection_settings(*args, **kwargs)
51107
return XSession(settings)
52108

53109

54-
def get_node_session(settings):
110+
def get_node_session(*args, **kwargs):
55111
"""Creates a NodeSession instance using the provided connection data.
56112
57113
Args:
58-
settings (dict): Connection data used to connect to the database.
114+
*args: Variable length argument list with the connection data used
115+
to connect to the database. It can be a dictionary or a
116+
connection string.
117+
**kwargs: Arbitrary keyword arguments with connection data used to
118+
connect to the database.
59119
60120
Returns:
61121
mysqlx.XSession: XSession object.
62122
"""
123+
settings = _get_connection_settings(*args, **kwargs)
63124
return NodeSession(settings)
64125

65126

tests/test_mysqlx_connection.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
# MySQL Connector/Python - MySQL driver written in Python.
23
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
34

@@ -33,6 +34,27 @@
3334

3435
LOGGER = logging.getLogger(tests.LOGGER_NAME)
3536

37+
_URI_TEST_RESULTS = ( # (uri, result)
38+
("127.0.0.1", None),
39+
("localhost", None),
40+
("domain.com", None),
41+
("user:[email protected]", {"database": "", "host": "127.0.0.1",
42+
"password": "password", "port": 33060,
43+
"user": "user"}),
44+
("user:@127.0.0.1", {"database": "", "host": "127.0.0.1", "password": "",
45+
"port": 33060, "user": "user"}),
46+
("mysqlx://user:@127.0.0.1", {"database": "", "host": "127.0.0.1",
47+
"password": "", "port": 33060,
48+
"user": "user"}),
49+
("mysqlx://user@[2001:db8:85a3:8d3:1319:8a2e:370:7348]:1", None),
50+
("mysqlx://user:password@[2001:db8:85a3:8d3:1319:8a2e:370:7348]:1",
51+
{"database": "", "host": "2001:db8:85a3:8d3:1319:8a2e:370:7348",
52+
"password": "password", "port": 1, "user": "user"}),
53+
("áé'í'óú:[email protected]",
54+
{"database": "", "host": "127.0.0.1", "password": "unicode",
55+
"port": 33060, "user": "áé'í'óú"}),
56+
)
57+
3658

3759
@unittest.skipIf(tests.MYSQL_VERSION < (5, 7, 12), "XPlugin not compatible")
3860
class MySQLxXSessionTests(tests.MySQLxTests):
@@ -54,6 +76,24 @@ def test___init__(self):
5476
}
5577
self.assertRaises(TypeError, mysqlx.XSession, bad_config)
5678

79+
def test_connection_uri(self):
80+
uri = ("mysqlx://{user}:{password}@{host}:{port}/{schema}"
81+
"".format(user=self.connect_kwargs["user"],
82+
password=self.connect_kwargs["password"],
83+
host=self.connect_kwargs["host"],
84+
port=self.connect_kwargs["port"],
85+
schema=self.connect_kwargs["database"]))
86+
session = mysqlx.get_session(uri)
87+
self.assertIsInstance(session, mysqlx.XSession)
88+
89+
# Test URI parser function
90+
for uri, res in _URI_TEST_RESULTS:
91+
try:
92+
settings = mysqlx._get_connection_settings(uri)
93+
self.assertEqual(res, settings)
94+
except mysqlx.Error:
95+
self.assertEqual(res, None)
96+
5797
def test_get_schema(self):
5898
schema = self.session.get_schema(self.schema_name)
5999
self.assertTrue(schema, mysqlx.Schema)
@@ -96,6 +136,24 @@ def test___init__(self):
96136
}
97137
self.assertRaises(TypeError, mysqlx.NodeSession, bad_config)
98138

139+
def test_connection_uri(self):
140+
uri = ("mysqlx://{user}:{password}@{host}:{port}/{schema}"
141+
"".format(user=self.connect_kwargs["user"],
142+
password=self.connect_kwargs["password"],
143+
host=self.connect_kwargs["host"],
144+
port=self.connect_kwargs["port"],
145+
schema=self.connect_kwargs["database"]))
146+
session = mysqlx.get_node_session(uri)
147+
self.assertIsInstance(session, mysqlx.NodeSession)
148+
149+
# Test URI parser function
150+
for uri, res in _URI_TEST_RESULTS:
151+
try:
152+
settings = mysqlx._get_connection_settings(uri)
153+
self.assertEqual(res, settings)
154+
except mysqlx.Error:
155+
self.assertEqual(res, None)
156+
99157
def test_get_schema(self):
100158
schema = self.session.get_schema(self.schema_name)
101159
self.assertTrue(schema, mysqlx.Schema)

0 commit comments

Comments
 (0)