From 2c6cff5af4f2abf8af2e45bcd7656fa9418b201e Mon Sep 17 00:00:00 2001 From: Tyghe Vallard Date: Tue, 28 Oct 2014 16:35:35 -0400 Subject: [PATCH 1/4] Adding in support to get attributes by attribute --- redmine/managers.py | 7 +++++++ tests/test_managers.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/redmine/managers.py b/redmine/managers.py index b527af8..fefcb9a 100644 --- a/redmine/managers.py +++ b/redmine/managers.py @@ -112,6 +112,13 @@ def new(self): """Returns new empty resource""" return self.to_resource({}) + def get_by_attribute(self, name, value): + """Returns an attribute by filtering down all items by name == value""" + for item in self.all(): + if getattr(item, name) == value: + return item + raise ResourceNotFoundError + def get(self, resource_id, **params): """Returns a Resource object directly by resource id (can be either integer id or string identifier)""" if self.resource_class.query_one is None or self.resource_class.container_one is None: diff --git a/tests/test_managers.py b/tests/test_managers.py index 22bfc8a..04df0ef 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -2,7 +2,11 @@ from redmine.managers import ResourceManager from redmine.resources import Project from redmine.resultsets import ResourceSet -from redmine.exceptions import ResourceBadMethodError, ValidationError +from redmine.exceptions import ( + ResourceBadMethodError, + ValidationError, + ResourceNotFoundError +) class FooResource(Project): @@ -105,6 +109,29 @@ def test_convert_dicts_to_resource_set_object(self): self.assertEqual(resourceset[1].identifier, 'bar') self.assertEqual(resourceset[1].id, 2) + @mock.patch('requests.get') + def test_get_resource_by_attribute_missing_attribute(self, mock_get): + from test_resources import responses + mock_get.return_value = response = mock.Mock(status_code=200) + response.json = json_response(responses['tracker']['all']) + self.assertRaises(ResourceAttrError, lambda: self.redmine.tracker.get_by_attribute('missing', 'Foo')) + + @mock.patch('requests.get') + def test_get_resource_by_attribute(self, mock_get): + from test_resources import responses + mock_get.return_value = response = mock.Mock(status_code=200) + response.json = json_response(responses['tracker']['all']) + foo = self.redmine.tracker.get_by_attribute('name', 'Foo') + bar = self.redmine.tracker.get_by_attribute('id', 2) + self.assertEqual('Foo', foo.name) + self.assertEqual('Bar', bar.name) + + @mock.patch('requests.get') + def test_get_resource_by_attribute_missing(self, mock_get): + mock_get.return_value = response = mock.Mock(status_code=200) + response.json = json_response({'trackers': []}) + self.assertRaises(ResourceNotFoundError, lambda: self.redmine.tracker.get_by_attribute('foo','bar')) + @mock.patch('requests.get') def test_get_single_resource(self, mock_get): mock_get.return_value = response = mock.Mock(status_code=200) From 25697d48f80ce9221d0a84d182f99536b94da207 Mon Sep 17 00:00:00 2001 From: Tyghe Vallard Date: Wed, 29 Oct 2014 11:49:14 -0400 Subject: [PATCH 2/4] Changing get_by_attribute to get_all_by_attribute --- redmine/managers.py | 10 +++++++--- tests/test_managers.py | 36 ++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/redmine/managers.py b/redmine/managers.py index fefcb9a..2494b73 100644 --- a/redmine/managers.py +++ b/redmine/managers.py @@ -112,12 +112,16 @@ def new(self): """Returns new empty resource""" return self.to_resource({}) - def get_by_attribute(self, name, value): + def get_all_by_attribute(self, name, value): """Returns an attribute by filtering down all items by name == value""" + found = [] for item in self.all(): if getattr(item, name) == value: - return item - raise ResourceNotFoundError + found.append(item) + if found: + return found + else: + raise ResourceNotFoundError def get(self, resource_id, **params): """Returns a Resource object directly by resource id (can be either integer id or string identifier)""" diff --git a/tests/test_managers.py b/tests/test_managers.py index 04df0ef..31812bd 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -5,7 +5,8 @@ from redmine.exceptions import ( ResourceBadMethodError, ValidationError, - ResourceNotFoundError + ResourceNotFoundError, + ResourceAttrError ) @@ -110,27 +111,38 @@ def test_convert_dicts_to_resource_set_object(self): self.assertEqual(resourceset[1].id, 2) @mock.patch('requests.get') - def test_get_resource_by_attribute_missing_attribute(self, mock_get): + def test_get_all_resource_by_attribute_missing_attribute(self, mock_get): from test_resources import responses mock_get.return_value = response = mock.Mock(status_code=200) response.json = json_response(responses['tracker']['all']) - self.assertRaises(ResourceAttrError, lambda: self.redmine.tracker.get_by_attribute('missing', 'Foo')) + self.assertRaises(ResourceAttrError, lambda: self.redmine.tracker.get_all_by_attribute('missing', 'Foo')) @mock.patch('requests.get') - def test_get_resource_by_attribute(self, mock_get): - from test_resources import responses + def test_get_all_resource_by_attribute(self, mock_get): + trackers = { + 'trackers': + [ + {'name': 'Foo', 'id': 1}, + {'name': 'Foo', 'id': 2}, + {'name': 'Bar', 'id': 3}, + ] + } mock_get.return_value = response = mock.Mock(status_code=200) - response.json = json_response(responses['tracker']['all']) - foo = self.redmine.tracker.get_by_attribute('name', 'Foo') - bar = self.redmine.tracker.get_by_attribute('id', 2) - self.assertEqual('Foo', foo.name) - self.assertEqual('Bar', bar.name) + response.json = json_response(trackers) + foo = list(self.redmine.tracker.get_all_by_attribute('name', 'Foo')) + bar = list(self.redmine.tracker.get_all_by_attribute('id', 3)) + self.assertEqual('Foo', foo[0].name) + self.assertEqual('Foo', foo[1].name) + self.assertEqual(1, foo[0].id) + self.assertEqual(2, foo[1].id) + self.assertEqual('Bar', bar[0].name) + self.assertEqual(3, bar[0].id) @mock.patch('requests.get') - def test_get_resource_by_attribute_missing(self, mock_get): + def test_get_all_resource_by_attribute_missing(self, mock_get): mock_get.return_value = response = mock.Mock(status_code=200) response.json = json_response({'trackers': []}) - self.assertRaises(ResourceNotFoundError, lambda: self.redmine.tracker.get_by_attribute('foo','bar')) + self.assertRaises(ResourceNotFoundError, lambda: self.redmine.tracker.get_all_by_attribute('foo','bar')) @mock.patch('requests.get') def test_get_single_resource(self, mock_get): From f82743c7848d5fed707da96eddf726f3e86d7246 Mon Sep 17 00:00:00 2001 From: Tyghe Vallard Date: Wed, 29 Oct 2014 11:59:28 -0400 Subject: [PATCH 3/4] Removed test_resources import to fix travis build error for python 3.2.5 --- tests/test_managers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_managers.py b/tests/test_managers.py index 31812bd..5b8c309 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -112,9 +112,8 @@ def test_convert_dicts_to_resource_set_object(self): @mock.patch('requests.get') def test_get_all_resource_by_attribute_missing_attribute(self, mock_get): - from test_resources import responses mock_get.return_value = response = mock.Mock(status_code=200) - response.json = json_response(responses['tracker']['all']) + response.json = json_response({'trackers': [{'name': 'Foo', 'id': 1}, {'name': 'Bar', 'id': 2}]}) self.assertRaises(ResourceAttrError, lambda: self.redmine.tracker.get_all_by_attribute('missing', 'Foo')) @mock.patch('requests.get') From 584b52452703a25c53f4c730c34a77c2be1a4cb7 Mon Sep 17 00:00:00 2001 From: Tyghe Vallard Date: Wed, 29 Oct 2014 13:41:30 -0400 Subject: [PATCH 4/4] get_all_by_attribute now returns an unevaluated generator and does not return an Exception if the result set is empty --- redmine/managers.py | 9 +-------- tests/test_managers.py | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/redmine/managers.py b/redmine/managers.py index 2494b73..09a5b8f 100644 --- a/redmine/managers.py +++ b/redmine/managers.py @@ -114,14 +114,7 @@ def new(self): def get_all_by_attribute(self, name, value): """Returns an attribute by filtering down all items by name == value""" - found = [] - for item in self.all(): - if getattr(item, name) == value: - found.append(item) - if found: - return found - else: - raise ResourceNotFoundError + return (item for item in self.all() if getattr(item, name) == value) def get(self, resource_id, **params): """Returns a Resource object directly by resource id (can be either integer id or string identifier)""" diff --git a/tests/test_managers.py b/tests/test_managers.py index 5b8c309..0c47ab2 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -111,13 +111,23 @@ def test_convert_dicts_to_resource_set_object(self): self.assertEqual(resourceset[1].id, 2) @mock.patch('requests.get') - def test_get_all_resource_by_attribute_missing_attribute(self, mock_get): + def test_get_all_by_attribute_returns_generator(self, mock_get): + import types + trackers = { + 'trackers': + [ + {'name': 'Foo', 'id': 1}, + {'name': 'Foo', 'id': 2}, + {'name': 'Bar', 'id': 3}, + ] + } mock_get.return_value = response = mock.Mock(status_code=200) - response.json = json_response({'trackers': [{'name': 'Foo', 'id': 1}, {'name': 'Bar', 'id': 2}]}) - self.assertRaises(ResourceAttrError, lambda: self.redmine.tracker.get_all_by_attribute('missing', 'Foo')) + response.json = json_response(trackers) + foo = self.redmine.tracker.get_all_by_attribute('name','Foo') + self.assertIsInstance(foo, types.GeneratorType) @mock.patch('requests.get') - def test_get_all_resource_by_attribute(self, mock_get): + def test_get_all_by_attribute(self, mock_get): trackers = { 'trackers': [ @@ -138,10 +148,10 @@ def test_get_all_resource_by_attribute(self, mock_get): self.assertEqual(3, bar[0].id) @mock.patch('requests.get') - def test_get_all_resource_by_attribute_missing(self, mock_get): + def test_get_all_by_attribute_returns_empty_recordset(self, mock_get): mock_get.return_value = response = mock.Mock(status_code=200) response.json = json_response({'trackers': []}) - self.assertRaises(ResourceNotFoundError, lambda: self.redmine.tracker.get_all_by_attribute('foo','bar')) + self.assertEqual([], list(self.redmine.tracker.get_all_by_attribute('foo','bar'))) @mock.patch('requests.get') def test_get_single_resource(self, mock_get):