From d73fea9eeed292ef3eff6944505e0bf0f1aa1900 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Thu, 1 Jan 2015 19:18:44 +0100 Subject: [PATCH 01/13] Fix typo in module doc --- osmapi/OsmApi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osmapi/OsmApi.py b/osmapi/OsmApi.py index 83a8670..7d2b0de 100644 --- a/osmapi/OsmApi.py +++ b/osmapi/OsmApi.py @@ -8,7 +8,7 @@ * **dictionary keys** are _unicode_ * **changeset** is _integer_ -* *version** is _integer_ +* **version** is _integer_ * **tag** is a _dictionary_ * **timestamp** is _unicode_ * **user** is _unicode_ From e5fd6dab5c5ef7c6add5ca05faea18b3061dbb5f Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Thu, 1 Jan 2015 19:24:23 +0100 Subject: [PATCH 02/13] Note about where to find this module --- osmapi/OsmApi.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osmapi/OsmApi.py b/osmapi/OsmApi.py index 7d2b0de..d96465f 100644 --- a/osmapi/OsmApi.py +++ b/osmapi/OsmApi.py @@ -4,6 +4,9 @@ The OsmApi module is a wrapper for the OpenStreetMap API. As such it provides an easy access to the functionality of the API. +You can find this module [on PyPI](https://pypi.python.org/pypi/osmapi) +or [on GitHub](https://github.com/metaodi/osmapi). + ## Notes: * **dictionary keys** are _unicode_ From fea48126320334570d1f23fb7143f10642c0027d Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Fri, 2 Jan 2015 02:19:11 +0100 Subject: [PATCH 03/13] Keep a changelog --- CHANGELOG.md | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6fb8ce0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,158 @@ +# Change Log +All notable changes to this project will be documented in this file. +This project follows [Semantic Versioning](http://semver.org/). + +## [Unreleased][unreleased] + +## 0.4.2 - 2015-01-01 +### Fixed +- Result of `NodeWay` is now actually parsed as a `way` + +### Added +- Lots of method comments for documentation + +### Changed +- Update to pdoc 0.3.1 which changed the appearance of the online docs + +## 0.4.1 - 2014-10-08 +### Changed +- Parse dates in notes as `datetime` objects + +## 0.4.0 - 2014-10-07 +### Added +- Release for OSM Notes API +- Generation of online documentation (http://osmapi.divshot.io) + +## 0.3.1 - 2014-06-21 +### Fixed +- Hotfix release of Python 3.x (base64) + +## 0.3.0 - 2014-05-20 +### Added +- Support for Python 3.x +- Use `tox` to run tests against multiple versions of Python + +## 0.2.26 - 2014-05-02 +### Fixed +- Fixed notes again + +## 0.2.25 - 2014-05-02 +### Fixed +- Unit tests for basic functionality +- Fixed based on the unit tests (previously undetected bugs) + +## 0.2.24 - 2014-01-07 +### Fixed +- Fixed notes + +## 0.2.23 - 2014-01-03 +### Changed +- Hotfix release + +## 0.2.22 - 2014-01-03 +### Fixed +- Fixed README.md not found error during installation + +## 0.2.21 - 2014-01-03 +### Changed +- Updated description + +## 0.2.20 - 2014-01-01 +### Added +- First release of PyPI package "osmapi" + +## 0.2.19 - 2014-01-01 +### Changed +- Inital version from SVN (http://svn.openstreetmap.org/applications/utils/python_lib/OsmApi/OsmApi.py) +- Move to GitHub + +## 0.2.19 - 2010-05-24 +### Changed +- Add debug message on ApiError + +## 0.2.18 - 2010-04-20 +### Fixed +- Fix ChangesetClose and _http_request + +## 0.2.17 - 2010-01-02 +### Added +- Capabilities implementation + +## 0.2.16 - 2010-01-02 +### Changed +- ChangesetsGet by Alexander Rampp + +## 0.2.15 - 2009-12-16 +### Fixed +- xml encoding error for < and > + +## 0.2.14 - 2009-11-20 +### Changed +- changesetautomulti parameter + +## 0.2.13 - 2009-11-16 +### Changed +- modify instead update for osc + +## 0.2.12 - 2009-11-14 +### Added +- raise ApiError on 4xx errors + +## 0.2.11 - 2009-10-14 +### Fixed +- unicode error on ChangesetUpload + +## 0.2.10 - 2009-10-14 +### Added +- RelationFullRecur definition + +## 0.2.9 - 2009-10-13 +### Added +- automatic changeset management +- ChangesetUpload implementation + +## 0.2.8 - 2009-10-13 +### Changed +- *(Create|Update|Delete) use not unique _do method + +## 0.2.7 - 2009-10-09 +### Added +- implement all missing functions except ChangesetsGet and GetCapabilities + +## 0.2.6 - 2009-10-09 +### Changed +- encoding clean-up + +## 0.2.5 - 2009-10-09 +### Added +- implements NodesGet, WaysGet, RelationsGet, ParseOsm, ParseOsc + +## 0.2.4 - 2009-10-06 clean-up +### Changed +- clean-up + +## 0.2.3 - 2009-09-09 +### Changed +- keep http connection alive for multiple request +- (Node|Way|Relation)Get return None when object have been deleted (raising error before) + +## 0.2.2 - 2009-07-13 +### Added +- can identify applications built on top of the lib + +## 0.2.1 - 2009-05-05 +### Changed +- some changes in constructor + +## 0.2 - 2009-05-01 +### Added +- initial import + + +# Categories +- `Added` for new features. +- `Changed` for changes in existing functionality. +- `Deprecated` for once-stable features removed in upcoming releases. +- `Removed` for deprecated features removed in this release. +- `Fixed` for any bug fixes. +- `Security` to invite users to upgrade in case of vulnerabilities. From 8a728836c534700627ed29300f7e98af5b57b214 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Thu, 1 Jan 2015 23:18:12 +0100 Subject: [PATCH 04/13] Parse dates as datetime objects --- osmapi/OsmApi.py | 18 ++++++++++++++++-- tests/changeset_tests.py | 11 ++++++----- tests/node_tests.py | 9 +++++---- tests/relation_tests.py | 3 ++- tests/way_tests.py | 3 ++- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/osmapi/OsmApi.py b/osmapi/OsmApi.py index d96465f..af324a0 100644 --- a/osmapi/OsmApi.py +++ b/osmapi/OsmApi.py @@ -1684,6 +1684,14 @@ def _DomGetAttributes(self, DomElement): # noqa v = (v == "true") elif k == "ref": v = int(v) + elif k == "comments_count": + v = int(v) + elif k == "timestamp": + v = self._ParseDate(v) + elif k == "created_at": + v = self._ParseDate(v) + elif k == "closed_at": + v = self._ParseDate(v) result[k] = v return result @@ -1785,10 +1793,16 @@ def _DomParseNote(self, DomElement): return result def _ParseDate(self, DateString): + result = DateString try: - return datetime.strptime(DateString, "%Y-%m-%d %H:%M:%S UTC") + result = datetime.strptime(DateString, "%Y-%m-%d %H:%M:%S UTC") except: - return None + try: + result = datetime.strptime(DateString, "%Y-%m-%dT%H:%M:%SZ") + except: + pass + + return result ################################################## # Internal xml builder # diff --git a/tests/changeset_tests.py b/tests/changeset_tests.py index 9901aea..3805ec6 100644 --- a/tests/changeset_tests.py +++ b/tests/changeset_tests.py @@ -3,6 +3,7 @@ from . import osmapi_tests import mock import xmltodict +import datetime try: import urlparse except: @@ -60,8 +61,8 @@ def test_ChangesetGet(self): self.assertEquals(result, { 'id': 123, - 'closed_at': '2009-09-07T22:57:37Z', - 'created_at': '2009-09-07T21:57:36Z', + 'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37), + 'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36), 'max_lat': '52.4710193', 'max_lon': '-1.4831815', 'min_lat': '45.9667901', @@ -491,7 +492,7 @@ def test_ChangesetDownload(self): 'tag': { 'highway': 'traffic_signals' }, - 'timestamp': '2013-05-14T10:33:04Z', + 'timestamp': datetime.datetime(2013, 5, 14, 10, 33, 4), 'uid': 1178, 'user': 'tyrTester06', 'version': 1, @@ -522,8 +523,8 @@ def test_ChangesetsGet(self): self.assertEquals(len(result), 10) self.assertEquals(result[41417], { - 'closed_at': '2014-04-29T20:25:01Z', - 'created_at': '2014-04-29T20:25:01Z', + 'closed_at': datetime.datetime(2014, 4, 29, 20, 25, 1), + 'created_at': datetime.datetime(2014, 4, 29, 20, 25, 1), 'id': 41417, 'max_lat': '58.8997467', 'max_lon': '22.7364427', diff --git a/tests/node_tests.py b/tests/node_tests.py index 1323d8e..f80a8cf 100644 --- a/tests/node_tests.py +++ b/tests/node_tests.py @@ -3,6 +3,7 @@ from . import osmapi_tests from osmapi import OsmApi import mock +import datetime class TestOsmApiNode(osmapi_tests.TestOsmApi): @@ -19,7 +20,7 @@ def test_NodeGet(self): 'id': 123, 'changeset': 15293, 'uid': 605, - 'timestamp': '2012-04-18T11:14:26Z', + 'timestamp': datetime.datetime(2012, 4, 18, 11, 14, 26), 'lat': 51.8753146, 'lon': -1.4857118, 'visible': True, @@ -45,7 +46,7 @@ def test_NodeGet_with_version(self): 'id': 123, 'changeset': 4152, 'uid': 605, - 'timestamp': '2011-04-18T11:14:26Z', + 'timestamp': datetime.datetime(2011, 4, 18, 11, 14, 26), 'lat': 51.8753146, 'lon': -1.4857118, 'visible': True, @@ -270,7 +271,7 @@ def test_NodesGet(self): 'id': 123, 'changeset': 15293, 'uid': 605, - 'timestamp': '2012-04-18T11:14:26Z', + 'timestamp': datetime.datetime(2012, 4, 18, 11, 14, 26), 'lat': 51.8753146, 'lon': -1.4857118, 'visible': True, @@ -285,7 +286,7 @@ def test_NodesGet(self): self.assertEquals(result[345], { 'id': 345, 'changeset': 244, - 'timestamp': '2009-09-12T03:22:59Z', + 'timestamp': datetime.datetime(2009, 9, 12, 3, 22, 59), 'uid': 1, 'visible': False, 'version': 2, diff --git a/tests/relation_tests.py b/tests/relation_tests.py index 60d1799..66d9c67 100644 --- a/tests/relation_tests.py +++ b/tests/relation_tests.py @@ -2,6 +2,7 @@ from nose.tools import * # noqa from . import osmapi_tests import mock +import datetime def debug(result): @@ -24,7 +25,7 @@ def test_RelationGet(self): 'id': 321, 'changeset': 434, 'uid': 12, - 'timestamp': '2009-09-15T22:24:25Z', + 'timestamp': datetime.datetime(2009, 9, 15, 22, 24, 25), 'visible': True, 'version': 1, 'user': 'green525', diff --git a/tests/way_tests.py b/tests/way_tests.py index ba332c4..8fdc969 100644 --- a/tests/way_tests.py +++ b/tests/way_tests.py @@ -2,6 +2,7 @@ from nose.tools import * # noqa from . import osmapi_tests import mock +import datetime class TestOsmApiWay(osmapi_tests.TestOsmApi): @@ -18,7 +19,7 @@ def test_WayGet(self): 'id': 321, 'changeset': 298, 'uid': 12, - 'timestamp': '2009-09-14T23:23:18Z', + 'timestamp': datetime.datetime(2009, 9, 14, 23, 23, 18), 'visible': True, 'version': 1, 'user': 'green525', From e572fd0a5abeffb9accfd05f7612261751c94d1f Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Fri, 2 Jan 2015 00:36:24 +0100 Subject: [PATCH 05/13] Implementation of changeset discussions - ChangesetComment - ChangesetSubscribe - ChangesetUnsubscribe - include_discussion parameter for ChangesetGet --- osmapi/OsmApi.py | 151 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/osmapi/OsmApi.py b/osmapi/OsmApi.py index af324a0..88e3e2b 100644 --- a/osmapi/OsmApi.py +++ b/osmapi/OsmApi.py @@ -71,6 +71,14 @@ def __str__(self): ) +class AlreadySubscribedApiError(ApiError): + pass + + +class NotSubscribedApiError(ApiError): + pass + + class OsmApi: """ Main class of osmapi, instanciate this class to use osmapi @@ -1011,7 +1019,7 @@ def RelationsGet(self, RelationIdList): # Changeset # ################################################## - def ChangesetGet(self, ChangesetId): + def ChangesetGet(self, ChangesetId, include_discussion=False): """ Returns changeset with `ChangesetId` as a dict: @@ -1023,6 +1031,7 @@ def ChangesetGet(self, ChangesetId): 'created_at': timestamp of creation of this changeset 'closed_at': timestamp when changeset was closed 'comments_count': amount of comments + 'discussion': [] list of comment dict (-> `include_discussion`) 'max_lon': maximum longitude of changes in this changeset 'max_lat': maximum latitude of changes in this changeset 'min_lon': minimum longitude of changes in this changeset @@ -1032,8 +1041,14 @@ def ChangesetGet(self, ChangesetId): } `ChangesetId` is the unique identifier of a changeset. + + If `include_discussion` is set to `True` the changeset discussion + will be available in the result. """ - data = self._get("/api/0.6/changeset/"+str(ChangesetId)) + path = "/api/0.6/changeset/"+str(ChangesetId) + if (include_discussion): + path = path + "?include_discussion=true" + data = self._get(path) data = xml.dom.minidom.parseString(data) data = data.getElementsByTagName("osm")[0] data = data.getElementsByTagName("changeset")[0] @@ -1214,6 +1229,119 @@ def ChangesetsGet( # noqa result[tmpCS["id"]] = tmpCS return result + def ChangesetComment(self, ChangesetId, comment): + """ + Adds a comment to the changeset `ChangesetId` + + `comment` should be a string. + + Returns the updated `ChangesetData` dict: + + #!python + { + 'id': id of Changeset, + 'open': True|False, wheter or not this changeset is open + 'tag': {} dict of tags, + 'created_at': timestamp of creation of this changeset + 'closed_at': timestamp when changeset was closed + 'comments_count': amount of comments + 'max_lon': maximum longitude of changes in this changeset + 'max_lat': maximum latitude of changes in this changeset + 'min_lon': minimum longitude of changes in this changeset + 'min_lat': minimum longitude of changes in this changeset + 'user': username of user that created this changeset, + 'uid': id of user that created this changeset, + } + + """ + params = urllib.urlencode({'text': comment}) + data = self._post( + "/api/0.6/changeset/"+str(ChangesetId)+"/comment", + params + ) + data = xml.dom.minidom.parseString(data) + data = data.getElementsByTagName("osm")[0] + data = data.getElementsByTagName("changeset")[0] + return self._DomParseChangeset(data) + + def ChangesetSubscribe(self, ChangesetId): + """ + Subcribe to the changeset discussion of changeset `ChangesetId`. + + The user will be informed about new comments (i.e. receive an email). + + Returns the updated `ChangesetData` dict: + + #!python + { + 'id': id of Changeset, + 'open': True|False, wheter or not this changeset is open + 'tag': {} dict of tags, + 'created_at': timestamp of creation of this changeset + 'closed_at': timestamp when changeset was closed + 'comments_count': amount of comments + 'max_lon': maximum longitude of changes in this changeset + 'max_lat': maximum latitude of changes in this changeset + 'min_lon': minimum longitude of changes in this changeset + 'min_lat': minimum longitude of changes in this changeset + 'user': username of user that created this changeset, + 'uid': id of user that created this changeset, + } + """ + try: + data = self._post( + "/api/0.6/changeset/"+str(ChangesetId)+"/subscribe", + None + ) + except ApiError as e: + if e.status == 409: + raise AlreadySubscribedApiError(e.status, e.reason, e.payload) + else: + raise + data = xml.dom.minidom.parseString(data) + data = data.getElementsByTagName("osm")[0] + data = data.getElementsByTagName("changeset")[0] + return self._DomParseChangeset(data) + + def ChangesetUnsubscribe(self, ChangesetId): + """ + Subcribe to the changeset discussion of changeset `ChangesetId`. + + The user will be informed about new comments (i.e. receive an email). + + Returns the updated `ChangesetData` dict: + + #!python + { + 'id': id of Changeset, + 'open': True|False, wheter or not this changeset is open + 'tag': {} dict of tags, + 'created_at': timestamp of creation of this changeset + 'closed_at': timestamp when changeset was closed + 'comments_count': amount of comments + 'max_lon': maximum longitude of changes in this changeset + 'max_lat': maximum latitude of changes in this changeset + 'min_lon': minimum longitude of changes in this changeset + 'min_lat': minimum longitude of changes in this changeset + 'user': username of user that created this changeset, + 'uid': id of user that created this changeset, + } + """ + try: + data = self._post( + "/api/0.6/changeset/"+str(ChangesetId)+"/unsubscribe", + None + ) + except ApiError as e: + if e.status == 404: + raise NotSubscribedApiError(e.status, e.reason, e.payload) + else: + raise + data = xml.dom.minidom.parseString(data) + data = data.getElementsByTagName("osm")[0] + data = data.getElementsByTagName("changeset")[0] + return self._DomParseChangeset(data) + ################################################## # Notes # ################################################## @@ -1692,6 +1820,8 @@ def _DomGetAttributes(self, DomElement): # noqa v = self._ParseDate(v) elif k == "closed_at": v = self._ParseDate(v) + elif k == "date": + v = self._ParseDate(v) result[k] = v return result @@ -1715,6 +1845,21 @@ def _DomGetNd(self, DomElement): result.append(int(int(t.attributes["ref"].value))) return result + def _DomGetDiscussion(self, DomElement): + """ + Returns the dictionnary of comments of a DomElement. + """ + result = [] + try: + discussion = DomElement.getElementsByTagName("discussion")[0] + for t in discussion.getElementsByTagName("comment"): + comment = self._DomGetAttributes(t) + comment['text'] = self._GetXmlValue(t, "text") + result.append(comment) + except IndexError: + pass + return result + def _DomGetComments(self, DomElement): """ Returns the list of comments of a DomElement. @@ -1772,6 +1917,8 @@ def _DomParseChangeset(self, DomElement): """ result = self._DomGetAttributes(DomElement) result["tag"] = self._DomGetTag(DomElement) + result["discussion"] = self._DomGetDiscussion(DomElement) + return result def _DomParseNote(self, DomElement): From e914c066a4b3c731b829deaa9a3249c1d400b0ab Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Fri, 2 Jan 2015 02:31:14 +0100 Subject: [PATCH 06/13] Describe changeset discussion changes in CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fb8ce0..2720fcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. This project follows [Semantic Versioning](http://semver.org/). ## [Unreleased][unreleased] +### Changed +- BC-break: all dates are now parsed as datetime objects + +### Added +- Implementation for changeset discussions (ChangesetComment, ChangesetSubscribe, ChangesetUnsubscribe) +- When (un)subscribing to a changeset, there are two special errors `AlreadySubscribedApiError` and `NotSubscribedApiError` to check for +- The ChangesetGet method got a new parameter `include_discussion` to determine wheter or not changeset discussion should be in the response ## 0.4.2 - 2015-01-01 ### Fixed From 32bf8abc38d7bc32618cc2cd2556ed62612bbcf5 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Fri, 2 Jan 2015 16:34:37 +0100 Subject: [PATCH 07/13] Note about CHANGELOG in docs --- osmapi/OsmApi.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osmapi/OsmApi.py b/osmapi/OsmApi.py index 88e3e2b..e9422c6 100644 --- a/osmapi/OsmApi.py +++ b/osmapi/OsmApi.py @@ -7,6 +7,10 @@ You can find this module [on PyPI](https://pypi.python.org/pypi/osmapi) or [on GitHub](https://github.com/metaodi/osmapi). +Find all information about changes of the different versions of this module +[in the CHANGELOG](https://github.com/metaodi/osmapi/blob/master/CHANGELOG.md). + + ## Notes: * **dictionary keys** are _unicode_ From 893e5e33905bcd1be1a7dc37560bdab87c620aa4 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 3 Jan 2015 11:28:59 +0100 Subject: [PATCH 08/13] Refactoring to make testing easier Now the HTTP connection can be mocked which allows for a more fine-grained inspection of the state and finally the http_request method is tested as well --- osmapi/OsmApi.py | 16 +++++--- tests/changeset_tests.py | 82 +++++++++++++++++++--------------------- tests/osmapi_tests.py | 32 ++++++++++++++-- 3 files changed, 79 insertions(+), 51 deletions(-) diff --git a/osmapi/OsmApi.py b/osmapi/OsmApi.py index e9422c6..74affbb 100644 --- a/osmapi/OsmApi.py +++ b/osmapi/OsmApi.py @@ -180,7 +180,7 @@ def __init__( self._CurrentChangesetId = 0 # Http connection - self._conn = httplib.HTTPConnection(self._api, 80) + self._conn = self._get_http_connection() def __del__(self): if self._changesetauto: @@ -1761,16 +1761,22 @@ def _http(self, cmd, path, auth, send): # noqa if i == 5: raise if i != 1: - time.sleep(5) - self._conn = httplib.HTTPConnection(self._api, 80) + self._sleep() + self._conn = self._get_http_connection() else: raise except Exception: if i == 5: raise if i != 1: - time.sleep(5) - self._conn = httplib.HTTPConnection(self._api, 80) + self._sleep() + self._conn = self._get_http_connection() + + def _get_http_connection(self): + return httplib.HTTPConnection(self._api, 80) + + def _sleep(self): + time.sleep(5) def _get(self, path): return self._http('GET', path, False, None) diff --git a/tests/changeset_tests.py b/tests/changeset_tests.py index 3805ec6..104d358 100644 --- a/tests/changeset_tests.py +++ b/tests/changeset_tests.py @@ -50,14 +50,13 @@ def debug(result): class TestOsmApiChangeset(osmapi_tests.TestOsmApi): def test_ChangesetGet(self): - self._http_mock() + self._conn_mock() result = self.api.ChangesetGet(123) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/changeset/123') - self.assertFalse(args[2]) self.assertEquals(result, { 'id': 123, @@ -77,7 +76,7 @@ def test_ChangesetGet(self): }) def test_ChangesetUpdate(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -91,12 +90,12 @@ def test_ChangesetUpdate(self): } ) - args, kwargs = self.api._http_request.call_args + args, _ = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/changeset/4444') - self.assertTrue(args[2]) + sendargs, _ = self.api._conn.send.call_args self.assertEquals( - xmltosorteddict(args[3]), + xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' b'\n' @@ -110,7 +109,7 @@ def test_ChangesetUpdate(self): self.assertEquals(result, 4444) def test_ChangesetUpdate_with_created_by(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -125,12 +124,12 @@ def test_ChangesetUpdate_with_created_by(self): } ) - args, kwargs = self.api._http_request.call_args + args, _ = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/changeset/4444') - self.assertTrue(args[2]) + sendargs, _ = self.api._conn.send.call_args self.assertEquals( - xmltosorteddict(args[3]), + xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' b'\n' @@ -144,7 +143,7 @@ def test_ChangesetUpdate_with_created_by(self): self.assertEquals(result, 4444) def test_ChangesetUpdate_wo_changeset(self): - self._http_mock() + self._conn_mock() with self.assertRaisesRegexp( Exception, @@ -156,7 +155,7 @@ def test_ChangesetUpdate_wo_changeset(self): ) def test_ChangesetCreate(self): - self._http_mock() + self._conn_mock(auth=True) result = self.api.ChangesetCreate( { @@ -164,12 +163,12 @@ def test_ChangesetCreate(self): } ) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/changeset/create') - self.assertTrue(args[2]) + sendargs, kwargs = self.api._conn.send.call_args self.assertEquals( - xmltosorteddict(args[3]), + xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' b'\n' @@ -183,7 +182,7 @@ def test_ChangesetCreate(self): self.assertEquals(result, 4321) def test_ChangesetCreate_with_created_by(self): - self._http_mock() + self._conn_mock(auth=True) result = self.api.ChangesetCreate( { @@ -192,12 +191,12 @@ def test_ChangesetCreate_with_created_by(self): } ) - args, kwargs = self.api._http_request.call_args + args, _ = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/changeset/create') - self.assertTrue(args[2]) + sendargs, _ = self.api._conn.send.call_args self.assertEquals( - xmltosorteddict(args[3]), + xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' b'\n' @@ -211,7 +210,7 @@ def test_ChangesetCreate_with_created_by(self): self.assertEquals(result, 1234) def test_ChangesetCreate_with_open_changeset(self): - self._http_mock() + self._conn_mock(auth=True) self.api.ChangesetCreate( { @@ -229,7 +228,7 @@ def test_ChangesetCreate_with_open_changeset(self): ) def test_ChangesetClose(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -239,13 +238,12 @@ def test_ChangesetClose(self): self.api.ChangesetClose() - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/changeset/4444/close') - self.assertTrue(args[2]) def test_ChangesetClose_with_no_changeset(self): - self._http_mock() + self._conn_mock() with self.assertRaisesRegexp( Exception, @@ -253,7 +251,7 @@ def test_ChangesetClose_with_no_changeset(self): self.api.ChangesetClose() def test_ChangesetUpload_create_node(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -278,12 +276,12 @@ def test_ChangesetUpload_create_node(self): result = self.api.ChangesetUpload(changesdata) - args, kwargs = self.api._http_request.call_args + args, _ = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'POST') self.assertEquals(args[1], '/api/0.6/changeset/4444/upload') - self.assertTrue(args[2]) + sendargs, _ = self.api._conn.send.call_args self.assertEquals( - xmltosorteddict(args[3]), + xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' b'\n' @@ -309,7 +307,7 @@ def test_ChangesetUpload_create_node(self): self.assertEquals(result[0]['data']['version'], 1) def test_ChangesetUpload_modify_way(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -352,12 +350,12 @@ def test_ChangesetUpload_modify_way(self): result = self.api.ChangesetUpload(changesdata) - args, kwargs = self.api._http_request.call_args + args, _ = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'POST') self.assertEquals(args[1], '/api/0.6/changeset/4444/upload') - self.assertTrue(args[2]) + sendargs, _ = self.api._conn.send.call_args self.assertEquals( - xmltosorteddict(args[3]), + xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' b'\n' @@ -398,7 +396,7 @@ def test_ChangesetUpload_modify_way(self): self.assertEquals(data['version'], 3) def test_ChangesetUpload_delete_relation(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -436,12 +434,12 @@ def test_ChangesetUpload_delete_relation(self): result = self.api.ChangesetUpload(changesdata) - args, kwargs = self.api._http_request.call_args + args, _ = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'POST') self.assertEquals(args[1], '/api/0.6/changeset/4444/upload') - self.assertTrue(args[2]) + sendargs, _ = self.api._conn.send.call_args self.assertEquals( - xmltosorteddict(args[3]), + xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' b'\n' @@ -469,14 +467,13 @@ def test_ChangesetUpload_delete_relation(self): self.assertNotIn('version', data) def test_ChangesetDownload(self): - self._http_mock() + self._conn_mock() result = self.api.ChangesetDownload(23123) - args, kwargs = self.api._http_request.call_args + args, _ = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/changeset/23123/download') - self.assertFalse(args[2]) self.assertEquals(len(result), 16) self.assertEquals( @@ -502,14 +499,14 @@ def test_ChangesetDownload(self): ) def test_ChangesetsGet(self): - self._http_mock() + self._conn_mock() result = self.api.ChangesetsGet( only_closed=True, username='metaodi' ) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals( dict(urlparse.parse_qsl(urlparse.urlparse(args[1])[4])), @@ -518,7 +515,6 @@ def test_ChangesetsGet(self): 'closed': '1' } ) - self.assertFalse(args[2]) self.assertEquals(len(result), 10) diff --git a/tests/osmapi_tests.py b/tests/osmapi_tests.py index dbb0521..a9afd3b 100644 --- a/tests/osmapi_tests.py +++ b/tests/osmapi_tests.py @@ -26,6 +26,34 @@ def setUp(self): self.maxDiff = None def _http_mock(self, filenames=None): + self.api._http_request = mock.Mock() + self.api._http_request.side_effect = self._return_values(filenames) + + def _conn_mock(self, auth=False, filenames=None, status=200, reason=None): + if auth: + self.api._username = 'testuser' + self.api._password = 'testpassword' + + response_mock = mock.Mock() + response_mock.status = status + response_mock.reason = reason + response_mock.read = mock.Mock( + side_effect=self._return_values(filenames) + ) + + conn_mock = mock.Mock() + conn_mock.putrequest = mock.Mock() + conn_mock.putheader = mock.Mock() + conn_mock.endheaders = mock.Mock() + conn_mock.send = mock.Mock() + conn_mock.getresponse = mock.Mock(return_value=response_mock) + + self.api._get_http_connection = mock.Mock(return_value=conn_mock) + self.api._conn = conn_mock + + self.api._sleep = mock.Mock() + + def _return_values(self, filenames): if filenames is None: filenames = [self._testMethodName + ".xml"] @@ -41,9 +69,7 @@ def _http_mock(self, filenames=None): return_values.append(file.read()) except: pass - - self.api._http_request = mock.Mock() - self.api._http_request.side_effect = return_values + return return_values def teardown(self): pass From fbb4e58a6875a59c5810282291012542b2a08008 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 3 Jan 2015 11:36:17 +0100 Subject: [PATCH 09/13] Add tests for changeset discussion features --- tests/changeset_tests.py | 163 ++++++++++++++++++ tests/fixtures/test_ChangesetComment.xml | 7 + .../fixtures/test_ChangesetGetWithComment.xml | 18 ++ tests/fixtures/test_ChangesetSubscribe.xml | 7 + ...hangesetSubscribeWhenAlreadySubscribed.xml | 1 + tests/fixtures/test_ChangesetUnsubscribe.xml | 7 + ..._ChangesetUnsubscribeWhenNotSubscribed.xml | 1 + 7 files changed, 204 insertions(+) create mode 100644 tests/fixtures/test_ChangesetComment.xml create mode 100644 tests/fixtures/test_ChangesetGetWithComment.xml create mode 100644 tests/fixtures/test_ChangesetSubscribe.xml create mode 100644 tests/fixtures/test_ChangesetSubscribeWhenAlreadySubscribed.xml create mode 100644 tests/fixtures/test_ChangesetUnsubscribe.xml create mode 100644 tests/fixtures/test_ChangesetUnsubscribeWhenNotSubscribed.xml diff --git a/tests/changeset_tests.py b/tests/changeset_tests.py index 104d358..ba14841 100644 --- a/tests/changeset_tests.py +++ b/tests/changeset_tests.py @@ -1,6 +1,7 @@ from __future__ import (unicode_literals, absolute_import) from nose.tools import * # noqa from . import osmapi_tests +from osmapi import AlreadySubscribedApiError, NotSubscribedApiError import mock import xmltodict import datetime @@ -62,6 +63,7 @@ def test_ChangesetGet(self): 'id': 123, 'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37), 'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36), + 'discussion': [], 'max_lat': '52.4710193', 'max_lon': '-1.4831815', 'min_lat': '45.9667901', @@ -522,6 +524,7 @@ def test_ChangesetsGet(self): 'closed_at': datetime.datetime(2014, 4, 29, 20, 25, 1), 'created_at': datetime.datetime(2014, 4, 29, 20, 25, 1), 'id': 41417, + 'discussion': [], 'max_lat': '58.8997467', 'max_lon': '22.7364427', 'min_lat': '58.8501594', @@ -535,3 +538,163 @@ def test_ChangesetsGet(self): 'uid': 1841, 'user': 'metaodi' }) + + def test_ChangesetGetWithComment(self): + self._conn_mock() + + result = self.api.ChangesetGet(52924, include_discussion=True) + + args, kwargs = self.api._conn.putrequest.call_args + self.assertEquals(args[0], 'GET') + self.assertEquals( + args[1], + '/api/0.6/changeset/52924?include_discussion=true' + ) + + self.assertEquals(result, { + 'id': 52924, + 'closed_at': datetime.datetime(2015, 1, 1, 14, 54, 2), + 'created_at': datetime.datetime(2015, 1, 1, 14, 54, 1), + 'comments_count': 3, + 'max_lat': '58.3369242', + 'max_lon': '25.8829107', + 'min_lat': '58.336813', + 'min_lon': '25.8823273', + 'discussion': [ + { + 'date': datetime.datetime(2015, 1, 1, 18, 56, 48), + 'text': 'test', + 'uid': 1841, + 'user': 'metaodi', + }, + { + 'date': datetime.datetime(2015, 1, 1, 18, 58, 3), + 'text': 'another comment', + 'uid': 1841, + 'user': 'metaodi', + }, + { + 'date': datetime.datetime(2015, 1, 1, 19, 16, 5), + 'text': 'hello', + 'uid': 1841, + 'user': 'metaodi', + }, + ], + 'open': False, + 'user': 'metaodi', + 'uid': 1841, + 'tag': { + 'comment': 'My test', + 'created_by': 'osmapi/0.4.1', + }, + }) + + def test_ChangesetComment(self): + self._conn_mock(auth=True) + + result = self.api.ChangesetComment( + 123, + comment="test comment" + ) + + args, _ = self.api._conn.putrequest.call_args + self.assertEquals(args[0], 'POST') + self.assertEquals(args[1], '/api/0.6/changeset/123/comment') + sendargs, _ = self.api._conn.send.call_args + self.assertEquals( + sendargs[0], + "text=test+comment" + ) + self.assertEquals(result, { + 'id': 123, + 'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37), + 'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36), + 'discussion': [], + 'max_lat': '52.4710193', + 'max_lon': '-1.4831815', + 'min_lat': '45.9667901', + 'min_lon': '-1.4998534', + 'open': False, + 'user': 'randomjunk', + 'uid': 3, + 'tag': { + 'comment': 'correct node bug', + 'created_by': 'Potlatch 1.2a', + }, + }) + + def test_ChangesetSubscribe(self): + self._conn_mock(auth=True) + + result = self.api.ChangesetSubscribe(123) + + args, _ = self.api._conn.putrequest.call_args + self.assertEquals(args[0], 'POST') + self.assertEquals(args[1], '/api/0.6/changeset/123/subscribe') + self.assertEquals(result, { + 'id': 123, + 'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37), + 'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36), + 'discussion': [], + 'max_lat': '52.4710193', + 'max_lon': '-1.4831815', + 'min_lat': '45.9667901', + 'min_lon': '-1.4998534', + 'open': False, + 'user': 'randomjunk', + 'uid': 3, + 'tag': { + 'comment': 'correct node bug', + 'created_by': 'Potlatch 1.2a', + }, + }) + + def test_ChangesetSubscribeWhenAlreadySubscribed(self): + self._conn_mock(auth=True, status=409) + + with self.assertRaises(AlreadySubscribedApiError) as cm: + self.api.ChangesetSubscribe(52924) + + self.assertEquals(cm.exception.status, 409) + self.assertEquals( + cm.exception.payload, + "You are already subscribed to changeset 52924." + ) + + def test_ChangesetUnsubscribe(self): + self._conn_mock(auth=True) + + result = self.api.ChangesetUnsubscribe(123) + + args, kwargs = self.api._conn.putrequest.call_args + self.assertEquals(args[0], 'POST') + self.assertEquals(args[1], '/api/0.6/changeset/123/unsubscribe') + self.assertEquals(result, { + 'id': 123, + 'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37), + 'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36), + 'discussion': [], + 'max_lat': '52.4710193', + 'max_lon': '-1.4831815', + 'min_lat': '45.9667901', + 'min_lon': '-1.4998534', + 'open': False, + 'user': 'randomjunk', + 'uid': 3, + 'tag': { + 'comment': 'correct node bug', + 'created_by': 'Potlatch 1.2a', + }, + }) + + def test_ChangesetUnsubscribeWhenNotSubscribed(self): + self._conn_mock(auth=True, status=404) + + with self.assertRaises(NotSubscribedApiError) as cm: + self.api.ChangesetUnsubscribe(52924) + + self.assertEquals(cm.exception.status, 404) + self.assertEquals( + cm.exception.payload, + "You are not subscribed to changeset 52924." + ) diff --git a/tests/fixtures/test_ChangesetComment.xml b/tests/fixtures/test_ChangesetComment.xml new file mode 100644 index 0000000..8e13b53 --- /dev/null +++ b/tests/fixtures/test_ChangesetComment.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/fixtures/test_ChangesetGetWithComment.xml b/tests/fixtures/test_ChangesetGetWithComment.xml new file mode 100644 index 0000000..2702340 --- /dev/null +++ b/tests/fixtures/test_ChangesetGetWithComment.xml @@ -0,0 +1,18 @@ + + + + + + + + test + + + another comment + + + hello + + + + diff --git a/tests/fixtures/test_ChangesetSubscribe.xml b/tests/fixtures/test_ChangesetSubscribe.xml new file mode 100644 index 0000000..8e13b53 --- /dev/null +++ b/tests/fixtures/test_ChangesetSubscribe.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/fixtures/test_ChangesetSubscribeWhenAlreadySubscribed.xml b/tests/fixtures/test_ChangesetSubscribeWhenAlreadySubscribed.xml new file mode 100644 index 0000000..11e71cb --- /dev/null +++ b/tests/fixtures/test_ChangesetSubscribeWhenAlreadySubscribed.xml @@ -0,0 +1 @@ +You are already subscribed to changeset 52924. diff --git a/tests/fixtures/test_ChangesetUnsubscribe.xml b/tests/fixtures/test_ChangesetUnsubscribe.xml new file mode 100644 index 0000000..8e13b53 --- /dev/null +++ b/tests/fixtures/test_ChangesetUnsubscribe.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/fixtures/test_ChangesetUnsubscribeWhenNotSubscribed.xml b/tests/fixtures/test_ChangesetUnsubscribeWhenNotSubscribed.xml new file mode 100644 index 0000000..69d1685 --- /dev/null +++ b/tests/fixtures/test_ChangesetUnsubscribeWhenNotSubscribed.xml @@ -0,0 +1 @@ +You are not subscribed to changeset 52924. From 8e019f7fec520bcf4f5fe22d0e7d1a79a038d540 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 3 Jan 2015 12:28:24 +0100 Subject: [PATCH 10/13] Refactoring tests to new conn_mock --- tests/capabilities_test.py | 2 +- tests/node_tests.py | 38 ++++++++++++++++++------------------ tests/notes_tests.py | 28 +++++++++++++------------- tests/osmapi_tests.py | 6 ++---- tests/relation_tests.py | 36 +++++++++++++++++----------------- tests/way_tests.py | 40 +++++++++++++++++++------------------- 6 files changed, 74 insertions(+), 76 deletions(-) diff --git a/tests/capabilities_test.py b/tests/capabilities_test.py index 2afd8cf..79b029e 100644 --- a/tests/capabilities_test.py +++ b/tests/capabilities_test.py @@ -5,7 +5,7 @@ class TestOsmApiNode(osmapi_tests.TestOsmApi): def test_Capabilities(self): - self._http_mock() + self._conn_mock() result = self.api.Capabilities() assert_equals(result, { diff --git a/tests/node_tests.py b/tests/node_tests.py index f80a8cf..4c6c0ea 100644 --- a/tests/node_tests.py +++ b/tests/node_tests.py @@ -8,11 +8,11 @@ class TestOsmApiNode(osmapi_tests.TestOsmApi): def test_NodeGet(self): - self._http_mock() + self._conn_mock() result = self.api.NodeGet(123) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/node/123') @@ -34,11 +34,11 @@ def test_NodeGet(self): }) def test_NodeGet_with_version(self): - self._http_mock() + self._conn_mock() result = self.api.NodeGet(123, NodeVersion=2) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/node/123/2') @@ -78,7 +78,7 @@ def test_NodeCreate_changesetauto(self): api="api06.dev.openstreetmap.org", changesetauto=True ) - self._http_mock(filenames=[ + self._conn_mock(auth=True, filenames=[ 'test_NodeCreate_changesetauto.xml', 'test_ChangesetUpload_create_node.xml', 'test_ChangesetClose.xml', @@ -96,7 +96,7 @@ def test_NodeCreate_changesetauto(self): self.assertIsNone(self.api.NodeCreate(test_node)) def test_NodeCreate(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -119,7 +119,7 @@ def test_NodeCreate(self): self.assertEquals(cs, 1111) result = self.api.NodeCreate(test_node) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/node/create') @@ -129,7 +129,7 @@ def test_NodeCreate(self): self.assertEquals(result['tag'], test_node['tag']) def test_NodeUpdate(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -153,7 +153,7 @@ def test_NodeUpdate(self): self.assertEquals(cs, 1111) result = self.api.NodeUpdate(test_node) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/node/7676') @@ -164,7 +164,7 @@ def test_NodeUpdate(self): self.assertEquals(result['tag'], test_node['tag']) def test_NodeDelete(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -183,18 +183,18 @@ def test_NodeDelete(self): result = self.api.NodeDelete(test_node) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'DELETE') self.assertEquals(args[1], '/api/0.6/node/7676') self.assertEquals(result['id'], 7676) self.assertEquals(result['version'], 4) def test_NodeHistory(self): - self._http_mock() + self._conn_mock() result = self.api.NodeHistory(123) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/node/123/history') @@ -211,11 +211,11 @@ def test_NodeHistory(self): ) def test_NodeWays(self): - self._http_mock() + self._conn_mock() result = self.api.NodeWays(234) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/node/234/ways') @@ -231,11 +231,11 @@ def test_NodeWays(self): ) def test_NodeRelations(self): - self._http_mock() + self._conn_mock() result = self.api.NodeRelations(4295668179) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/node/4295668179/relations') @@ -258,11 +258,11 @@ def test_NodeRelations(self): ) def test_NodesGet(self): - self._http_mock() + self._conn_mock() result = self.api.NodesGet([123, 345]) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/nodes?nodes=123,345') diff --git a/tests/notes_tests.py b/tests/notes_tests.py index 06770b3..596d884 100644 --- a/tests/notes_tests.py +++ b/tests/notes_tests.py @@ -11,7 +11,7 @@ class TestOsmApiNotes(osmapi_tests.TestOsmApi): def test_NotesGet(self): - self._http_mock() + self._conn_mock() result = self.api.NotesGet( -1.4998534, @@ -20,7 +20,7 @@ def test_NotesGet(self): 52.4710193 ) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') urlParts = urlparse.urlparse(args[1]) @@ -65,11 +65,11 @@ def test_NotesGet(self): }) def test_NoteGet(self): - self._http_mock() + self._conn_mock() result = self.api.NoteGet(1111) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/notes/1111') @@ -101,7 +101,7 @@ def test_NoteGet(self): }) def test_NoteCreate(self): - self._http_mock() + self._conn_mock(auth=True) note = { 'lat': 47.123, @@ -110,7 +110,7 @@ def test_NoteCreate(self): } result = self.api.NoteCreate(note) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'POST') urlParts = urlparse.urlparse(args[1]) @@ -139,11 +139,11 @@ def test_NoteCreate(self): }) def test_NoteComment(self): - self._http_mock() + self._conn_mock(auth=True) result = self.api.NoteComment(812, 'This is a comment') - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'POST') self.assertEquals( args[1], @@ -178,11 +178,11 @@ def test_NoteComment(self): }) def test_NoteClose(self): - self._http_mock() + self._conn_mock(auth=True) result = self.api.NoteClose(814, 'Close this note!') - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'POST') self.assertEquals( args[1], @@ -217,11 +217,11 @@ def test_NoteClose(self): }) def test_NoteReopen(self): - self._http_mock() + self._conn_mock(auth=True) result = self.api.NoteReopen(815, 'Reopen this note!') - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'POST') self.assertEquals( args[1], @@ -264,11 +264,11 @@ def test_NoteReopen(self): }) def test_NotesSearch(self): - self._http_mock() + self._conn_mock() result = self.api.NotesSearch('street') - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') urlParts = urlparse.urlparse(args[1]) diff --git a/tests/osmapi_tests.py b/tests/osmapi_tests.py index a9afd3b..e6e5e4a 100644 --- a/tests/osmapi_tests.py +++ b/tests/osmapi_tests.py @@ -24,10 +24,8 @@ def setUp(self): api="api06.dev.openstreetmap.org" ) self.maxDiff = None - - def _http_mock(self, filenames=None): - self.api._http_request = mock.Mock() - self.api._http_request.side_effect = self._return_values(filenames) + print(self._testMethodName) + print(self.api) def _conn_mock(self, auth=False, filenames=None, status=200, reason=None): if auth: diff --git a/tests/relation_tests.py b/tests/relation_tests.py index 66d9c67..82b85ad 100644 --- a/tests/relation_tests.py +++ b/tests/relation_tests.py @@ -13,11 +13,11 @@ def debug(result): class TestOsmApiRelation(osmapi_tests.TestOsmApi): def test_RelationGet(self): - self._http_mock() + self._conn_mock() result = self.api.RelationGet(321) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/relation/321') @@ -84,11 +84,11 @@ def test_RelationGet(self): }) def test_RelationGet_with_version(self): - self._http_mock() + self._conn_mock() result = self.api.RelationGet(765, 2) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/relation/765/2') @@ -98,7 +98,7 @@ def test_RelationGet_with_version(self): self.assertEquals(result['tag']['source'], 'test') def test_RelationCreate(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -131,7 +131,7 @@ def test_RelationCreate(self): result = self.api.RelationCreate(test_relation) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/relation/create') @@ -141,7 +141,7 @@ def test_RelationCreate(self): self.assertEquals(result['tag'], test_relation['tag']) def test_RelationUpdate(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -170,7 +170,7 @@ def test_RelationUpdate(self): result = self.api.RelationUpdate(test_relation) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/relation/8989') @@ -180,7 +180,7 @@ def test_RelationUpdate(self): self.assertEquals(result['tag'], test_relation['tag']) def test_RelationDelete(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -199,7 +199,7 @@ def test_RelationDelete(self): result = self.api.RelationDelete(test_relation) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'DELETE') self.assertEquals(args[1], '/api/0.6/relation/8989') @@ -207,11 +207,11 @@ def test_RelationDelete(self): self.assertEquals(result['version'], 43) def test_RelationHistory(self): - self._http_mock() + self._conn_mock() result = self.api.RelationHistory(2470397) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/relation/2470397/history') @@ -227,11 +227,11 @@ def test_RelationHistory(self): self.assertEquals(result[2]['version'], 2) def test_RelationRelations(self): - self._http_mock() + self._conn_mock() result = self.api.RelationRelations(1532552) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/relation/1532552/relations') @@ -246,11 +246,11 @@ def test_RelationRelations(self): ) def test_RelationFull(self): - self._http_mock() + self._conn_mock() result = self.api.RelationFull(2470397) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/relation/2470397/full') @@ -263,11 +263,11 @@ def test_RelationFull(self): self.assertEquals(result[10]['type'], 'relation') def test_RelationsGet(self): - self._http_mock() + self._conn_mock() result = self.api.RelationsGet([1532552, 1532553]) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals( args[1], diff --git a/tests/way_tests.py b/tests/way_tests.py index 8fdc969..233d249 100644 --- a/tests/way_tests.py +++ b/tests/way_tests.py @@ -7,11 +7,11 @@ class TestOsmApiWay(osmapi_tests.TestOsmApi): def test_WayGet(self): - self._http_mock() + self._conn_mock() result = self.api.WayGet(321) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/way/321') @@ -49,11 +49,11 @@ def test_WayGet(self): }) def test_WayGet_with_version(self): - self._http_mock() + self._conn_mock() result = self.api.WayGet(4294967296, 2) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/way/4294967296/2') @@ -62,18 +62,18 @@ def test_WayGet_with_version(self): self.assertEquals(result['user'], 'metaodi') def test_WayGet_nodata(self): - self._http_mock() + self._conn_mock() result = self.api.WayGet(321) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/way/321') self.assertEquals(result, '') def test_WayCreate(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -96,7 +96,7 @@ def test_WayCreate(self): result = self.api.WayCreate(test_way) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/way/create') @@ -105,7 +105,7 @@ def test_WayCreate(self): self.assertEquals(result['tag'], test_way['tag']) def test_WayUpdate(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -129,7 +129,7 @@ def test_WayUpdate(self): result = self.api.WayUpdate(test_way) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'PUT') self.assertEquals(args[1], '/api/0.6/way/876') @@ -139,7 +139,7 @@ def test_WayUpdate(self): self.assertEquals(result['tag'], test_way['tag']) def test_WayDelete(self): - self._http_mock() + self._conn_mock(auth=True) # setup mock self.api.ChangesetCreate = mock.Mock( @@ -158,18 +158,18 @@ def test_WayDelete(self): result = self.api.WayDelete(test_way) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'DELETE') self.assertEquals(args[1], '/api/0.6/way/876') self.assertEquals(result['id'], 876) self.assertEquals(result['version'], 8) def test_WayHistory(self): - self._http_mock() + self._conn_mock() result = self.api.WayHistory(4294967296) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/way/4294967296/history') @@ -184,11 +184,11 @@ def test_WayHistory(self): ) def test_WayRelations(self): - self._http_mock() + self._conn_mock() result = self.api.WayRelations(4295032193) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/way/4295032193/relations') @@ -211,11 +211,11 @@ def test_WayRelations(self): ) def test_WayFull(self): - self._http_mock() + self._conn_mock() result = self.api.WayFull(321) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/way/321/full') @@ -228,11 +228,11 @@ def test_WayFull(self): self.assertEquals(result[16]['type'], 'way') def test_WaysGet(self): - self._http_mock() + self._conn_mock() result = self.api.WaysGet([456, 678]) - args, kwargs = self.api._http_request.call_args + args, kwargs = self.api._conn.putrequest.call_args self.assertEquals(args[0], 'GET') self.assertEquals(args[1], '/api/0.6/ways?ways=456,678') From c9f3516685c71fd876e59ef294de434691abc0a8 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 3 Jan 2015 12:35:20 +0100 Subject: [PATCH 11/13] Tests for anonymous notes creation and comment --- tests/fixtures/test_NoteCommentAnonymous.xml | 25 +++++++ tests/fixtures/test_NoteCreateAnonymous.xml | 19 +++++ tests/notes_tests.py | 77 ++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 tests/fixtures/test_NoteCommentAnonymous.xml create mode 100644 tests/fixtures/test_NoteCreateAnonymous.xml diff --git a/tests/fixtures/test_NoteCommentAnonymous.xml b/tests/fixtures/test_NoteCommentAnonymous.xml new file mode 100644 index 0000000..772934e --- /dev/null +++ b/tests/fixtures/test_NoteCommentAnonymous.xml @@ -0,0 +1,25 @@ + + + + 842 + http://api06.dev.openstreetmap.org/api/0.6/notes/842 + http://api06.dev.openstreetmap.org/api/0.6/notes/842/comment + http://api06.dev.openstreetmap.org/api/0.6/notes/842/close + 2015-01-03 10:49:39 UTC + open + + + 2015-01-03 10:49:39 UTC + opened + test 123 + <p>test 123</p> + + + 2015-01-03 11:06:00 UTC + commented + blubb + <p>blubb</p> + + + + diff --git a/tests/fixtures/test_NoteCreateAnonymous.xml b/tests/fixtures/test_NoteCreateAnonymous.xml new file mode 100644 index 0000000..5dece43 --- /dev/null +++ b/tests/fixtures/test_NoteCreateAnonymous.xml @@ -0,0 +1,19 @@ + + + + 842 + http://api06.dev.openstreetmap.org/api/0.6/notes/842 + http://api06.dev.openstreetmap.org/api/0.6/notes/842/comment + http://api06.dev.openstreetmap.org/api/0.6/notes/842/close + 2015-01-03 10:49:39 UTC + open + + + 2015-01-03 10:49:39 UTC + opened + test 123 + <p>test 123</p> + + + + diff --git a/tests/notes_tests.py b/tests/notes_tests.py index 596d884..d6121e3 100644 --- a/tests/notes_tests.py +++ b/tests/notes_tests.py @@ -138,6 +138,44 @@ def test_NoteCreate(self): ] }) + def test_NoteCreateAnonymous(self): + self._conn_mock() + + note = { + 'lat': 47.123, + 'lon': 8.432, + 'text': 'test 123' + } + result = self.api.NoteCreate(note) + + args, kwargs = self.api._conn.putrequest.call_args + self.assertEquals(args[0], 'POST') + + urlParts = urlparse.urlparse(args[1]) + params = urlparse.parse_qs(urlParts.query) + self.assertEquals(params['lat'][0], '47.123') + self.assertEquals(params['lon'][0], '8.432') + self.assertEquals(params['text'][0], 'test 123') + + self.assertEquals(result, { + 'id': '842', + 'lat': 58.3368222, + 'lon': 25.8826183, + 'date_created': datetime(2015, 1, 3, 10, 49, 39), + 'date_closed': None, + 'status': 'open', + 'comments': [ + { + 'date': datetime(2015, 1, 3, 10, 49, 39), + 'action': 'opened', + 'text': "test 123", + 'html': "

test 123

", + 'uid': None, + 'user': None, + } + ] + }) + def test_NoteComment(self): self._conn_mock(auth=True) @@ -177,6 +215,45 @@ def test_NoteComment(self): ] }) + def test_NoteCommentAnonymous(self): + self._conn_mock() + + result = self.api.NoteComment(842, 'blubb') + + args, kwargs = self.api._conn.putrequest.call_args + self.assertEquals(args[0], 'POST') + self.assertEquals( + args[1], + '/api/0.6/notes/842/comment?text=blubb' + ) + + self.assertEquals(result, { + 'id': '842', + 'lat': 58.3368222, + 'lon': 25.8826183, + 'date_created': datetime(2015, 1, 3, 10, 49, 39), + 'date_closed': None, + 'status': 'open', + 'comments': [ + { + 'date': datetime(2015, 1, 3, 10, 49, 39), + 'action': 'opened', + 'text': "test 123", + 'html': "

test 123

", + 'uid': None, + 'user': None, + }, + { + 'date': datetime(2015, 1, 3, 11, 6, 0), + 'action': 'commented', + 'text': "blubb", + 'html': "

blubb

", + 'uid': None, + 'user': None, + } + ] + }) + def test_NoteClose(self): self._conn_mock(auth=True) From 4a5b669ad39a00fdd8abaa17e8443002651dec23 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 3 Jan 2015 12:58:33 +0100 Subject: [PATCH 12/13] Add test for UsernamePasswordMissingError exception --- tests/node_tests.py | 54 +++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/tests/node_tests.py b/tests/node_tests.py index 4c6c0ea..b435c70 100644 --- a/tests/node_tests.py +++ b/tests/node_tests.py @@ -1,7 +1,7 @@ from __future__ import (unicode_literals, absolute_import) from nose.tools import * # noqa from . import osmapi_tests -from osmapi import OsmApi +from osmapi import OsmApi, UsernamePasswordMissingError import mock import datetime @@ -57,21 +57,6 @@ def test_NodeGet_with_version(self): }, }) - def test_NodeCreate_wo_changeset(self): - test_node = { - 'lat': 47.287, - 'lon': 8.765, - 'tag': { - 'amenity': 'place_of_worship', - 'religion': 'pastafarian' - } - } - - with self.assertRaisesRegexp( - Exception, - 'need to open a changeset'): - self.api.NodeCreate(test_node) - def test_NodeCreate_changesetauto(self): # setup mock self.api = OsmApi( @@ -128,6 +113,43 @@ def test_NodeCreate(self): self.assertEquals(result['lon'], test_node['lon']) self.assertEquals(result['tag'], test_node['tag']) + def test_NodeCreate_wo_changeset(self): + test_node = { + 'lat': 47.287, + 'lon': 8.765, + 'tag': { + 'amenity': 'place_of_worship', + 'religion': 'pastafarian' + } + } + + with self.assertRaisesRegexp( + Exception, + 'need to open a changeset'): + self.api.NodeCreate(test_node) + + def test_NodeCreate_wo_auth(self): + self._conn_mock() + + # setup mock + self.api.ChangesetCreate = mock.Mock( + return_value=1111 + ) + self.api._CurrentChangesetId = 1111 + test_node = { + 'lat': 47.287, + 'lon': 8.765, + 'tag': { + 'amenity': 'place_of_worship', + 'religion': 'pastafarian' + } + } + + with self.assertRaisesRegexp( + UsernamePasswordMissingError, + 'Username/Password missing'): + self.api.NodeCreate(test_node) + def test_NodeUpdate(self): self._conn_mock(auth=True) From d9aa5b594a4bba9a1fce40593f2510a0e658ff78 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 3 Jan 2015 15:08:44 +0100 Subject: [PATCH 13/13] Release 0.5.0 --- CHANGELOG.md | 2 ++ osmapi/__init__.py | 2 +- tests/changeset_tests.py | 18 +++++++++--------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2720fcf..02d3060 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. This project follows [Semantic Versioning](http://semver.org/). ## [Unreleased][unreleased] + +## 0.5.0 - 2015-01-03 ### Changed - BC-break: all dates are now parsed as datetime objects diff --git a/osmapi/__init__.py b/osmapi/__init__.py index c3da58b..ddb4e18 100644 --- a/osmapi/__init__.py +++ b/osmapi/__init__.py @@ -1,5 +1,5 @@ from __future__ import (absolute_import, print_function, unicode_literals) -__version__ = '0.4.2' +__version__ = '0.5.0' from .OsmApi import * # noqa diff --git a/tests/changeset_tests.py b/tests/changeset_tests.py index ba14841..7024a23 100644 --- a/tests/changeset_tests.py +++ b/tests/changeset_tests.py @@ -100,10 +100,10 @@ def test_ChangesetUpdate(self): xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' - b'\n' + b'\n' b' \n' b' \n' - b' \n' + b' \n' b' \n' b'\n' ) @@ -134,7 +134,7 @@ def test_ChangesetUpdate_with_created_by(self): xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' - b'\n' + b'\n' b' \n' b' \n' b' \n' @@ -173,10 +173,10 @@ def test_ChangesetCreate(self): xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' - b'\n' + b'\n' b' \n' b' \n' - b' \n' + b' \n' b' \n' b'\n' ) @@ -201,7 +201,7 @@ def test_ChangesetCreate_with_created_by(self): xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' - b'\n' + b'\n' b' \n' b' \n' b' \n' @@ -286,7 +286,7 @@ def test_ChangesetUpload_create_node(self): xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' - b'\n' + b'\n' b'\n' b' \n' @@ -360,7 +360,7 @@ def test_ChangesetUpload_modify_way(self): xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' - b'\n' + b'\n' b'\n' b' \n' @@ -444,7 +444,7 @@ def test_ChangesetUpload_delete_relation(self): xmltosorteddict(sendargs[0]), xmltosorteddict( b'\n' - b'\n' + b'\n' b'\n' b' \n'