[lxc-devel] [pylxd/master] Remove overzealous '_' -> '-' subsitution in _APINode
ajkavanagh on Github
lxc-bot at linuxcontainers.org
Tue Apr 17 15:30:30 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 608 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180417/7d5f8d9f/attachment.bin>
-------------- next part --------------
From 27420d33c6ee230fd9099d680fcf170a8840e7cb Mon Sep 17 00:00:00 2001
From: Alex Kavanagh <alex at ajkavanagh.co.uk>
Date: Tue, 17 Apr 2018 16:27:12 +0100
Subject: [PATCH] Remove overzealous '_' -> '-' subsitution in _APINode
The fix for storage pools in the __getattr__() in _APINode has
affected the names of containers and snapshots, if '_' are used in
the name. This reverts most of that fix, adds tests, and special cases
'storage_pools' -> 'storage-pools' as an attribute ONLY, and not as
a name of a item.
Fixes: #295
---
pylxd/client.py | 37 +++++++++++++++++++++++++------------
pylxd/tests/test_client.py | 45 ++++++++++++++++++++-------------------------
2 files changed, 45 insertions(+), 37 deletions(-)
diff --git a/pylxd/client.py b/pylxd/client.py
index e8622e3..22d5902 100644
--- a/pylxd/client.py
+++ b/pylxd/client.py
@@ -60,20 +60,33 @@ def __init__(self, api_endpoint, cert=None, verify=True, timeout=None):
self.session.verify = verify
def __getattr__(self, name):
- # name here correspoinds to the model name in the LXD API
- # and, as such, must have underscores replaced with hyphens
- return self.__class__(
- '{}/{}'.format(self._api_endpoint, name.replace('_', '-')),
- cert=self.session.cert, verify=self.session.verify)
+ """Converts attribute lookup into the next /<segment> of an api
+ url.
+
+ :param name: the next segment
+ :type name: str
+ :returns: new _APINode with /<name> on the end
+ :rtype: _APINode
+ """
+ # Special case for storage_pools which needs to become 'storage-pools'
+ if name == 'storage_pools':
+ name = 'storage-pools'
+ return self.__class__('{}/{}'.format(self._api_endpoint, name),
+ cert=self.session.cert,
+ verify=self.session.verify)
def __getitem__(self, item):
- # item here correspoinds to the model name in the LXD API
- # and, as such, must have underscores replaced with hyphens
- return self.__class__(
- '{}/{}'.format(self._api_endpoint, item.replace('_', '-')),
- cert=self.session.cert,
- verify=self.session.verify,
- timeout=self._timeout)
+ """This converts python api.thing[name] -> ".../thing/name"
+
+ :param item: the 'thing' in the square-braces in a python expr.
+ :type item: str
+ :returns: A new _APINode(with the new item tagged on as /<item>
+ :rtype: _APINode
+ """
+ return self.__class__('{}/{}'.format(self._api_endpoint, item),
+ cert=self.session.cert,
+ verify=self.session.verify,
+ timeout=self._timeout)
def _assert_response(self, response, allowed_status_codes=(200,),
stream=False, is_api=True):
diff --git a/pylxd/tests/test_client.py b/pylxd/tests/test_client.py
index 5762c5a..f0d48db 100644
--- a/pylxd/tests/test_client.py
+++ b/pylxd/tests/test_client.py
@@ -246,31 +246,45 @@ class TestAPINode(unittest.TestCase):
def test_getattr(self):
"""API Nodes can use object notation for nesting."""
node = client._APINode('http://test.com')
-
new_node = node.test
-
self.assertEqual(
'http://test.com/test', new_node._api_endpoint)
+ def test_getattr_storage_pools(self):
+ """API node with storage_pool should be storage-pool"""
+ node = client._APINode('http://test.com')
+ new_node = node.test.storage_pools
+ self.assertEqual(
+ 'http://test.com/test/storage-pools', new_node._api_endpoint)
+ # other _ should stay as they were.
+ new_node = node.test.some_thing
+ self.assertEqual(
+ 'http://test.com/test/some_thing', new_node._api_endpoint)
+
def test_getitem(self):
"""API Nodes can use dict notation for nesting."""
node = client._APINode('http://test.com')
-
new_node = node['test']
-
self.assertEqual(
'http://test.com/test', new_node._api_endpoint)
+ def test_getitem_leave_underscores_alone(self):
+ """Bug 295 erronously changed underscores to '-' -- let's make sure
+ it doens't happend again
+ """
+ node = client._APINode('http://test.com')
+ new_node = node.thing['my_snapshot']
+ self.assertEqual(
+ 'http://test.com/thing/my_snapshot', new_node._api_endpoint)
+
def test_session_http(self):
"""HTTP nodes return the default requests session."""
node = client._APINode('http://test.com')
-
self.assertIsInstance(node.session, requests.Session)
def test_session_unix_socket(self):
"""HTTP nodes return a requests_unixsocket session."""
node = client._APINode('http+unix://test.com')
-
self.assertIsInstance(node.session, requests_unixsocket.Session)
@mock.patch('pylxd.client.requests.Session')
@@ -284,9 +298,7 @@ def test_get(self, Session):
Session.return_value = session
node = client._APINode('http://test.com')
-
node.get()
-
session.get.assert_called_once_with('http://test.com', timeout=None)
@mock.patch('pylxd.client.requests.Session')
@@ -298,11 +310,8 @@ def test_post(self, Session):
})
session = mock.Mock(**{'post.return_value': response})
Session.return_value = session
-
node = client._APINode('http://test.com')
-
node.post()
-
session.post.assert_called_once_with('http://test.com', timeout=None)
@mock.patch('pylxd.client.requests.Session')
@@ -314,9 +323,7 @@ def test_post_200_not_sync(self, Session):
})
session = mock.Mock(**{'post.return_value': response})
Session.return_value = session
-
node = client._APINode('http://test.com')
-
self.assertRaises(
exceptions.LXDAPIException,
node.post)
@@ -330,9 +337,7 @@ def test_post_missing_type_200(self, Session):
})
session = mock.Mock(**{'post.return_value': response})
Session.return_value = session
-
node = client._APINode('http://test.com')
-
self.assertRaises(
exceptions.LXDAPIException,
node.post)
@@ -346,11 +351,8 @@ def test_put(self, Session):
})
session = mock.Mock(**{'put.return_value': response})
Session.return_value = session
-
node = client._APINode('http://test.com')
-
node.put()
-
session.put.assert_called_once_with('http://test.com', timeout=None)
@mock.patch('pylxd.client.requests.Session')
@@ -362,11 +364,8 @@ def test_delete(self, Session):
})
session = mock.Mock(**{'delete.return_value': response})
Session.return_value = session
-
node = client._APINode('http://test.com')
-
node.delete()
-
session.delete.assert_called_once_with('http://test.com', timeout=None)
@@ -377,9 +376,7 @@ class TestWebsocketClient(unittest.TestCase):
def test_handshake_ok(self):
"""A `message` attribute of an empty list is created."""
ws_client = client._WebsocketClient('ws://an/fake/path')
-
ws_client.handshake_ok()
-
self.assertEqual([], ws_client.messages)
@requires_ws4py
@@ -388,7 +385,5 @@ def test_received_message(self):
message = mock.Mock(data=json.dumps({'test': 'data'}).encode('utf-8'))
ws_client = client._WebsocketClient('ws://an/fake/path')
ws_client.handshake_ok()
-
ws_client.received_message(message)
-
self.assertEqual({'test': 'data'}, ws_client.messages[0])
More information about the lxc-devel
mailing list