From 2e3ef8103ee9525448fa62566c92f168208aa152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Gy=C3=B6ngy=C3=B6si?= Date: Sun, 20 Jul 2025 02:30:27 +0200 Subject: [PATCH 1/4] Don't raise UsernamePasswordMissingError if Authorization header present Also, update the exception message and unit tests. --- osmapi/http.py | 6 ++++-- tests/changeset_test.py | 16 ++++++++++++---- tests/node_test.py | 5 ++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osmapi/http.py b/osmapi/http.py index dae3d61..8814157 100644 --- a/osmapi/http.py +++ b/osmapi/http.py @@ -66,8 +66,10 @@ def _http_request(self, method, path, auth, send, return_value=True): # noqa # Add API base URL to path path = self._api + path - if auth and not self._auth: - raise errors.UsernamePasswordMissingError("Username/Password missing") + if auth and not (self._auth or self._session.headers.get("Authorization")): + raise errors.UsernamePasswordMissingError( + "No username/password or 'Authorization' header provided" + ) try: response = self._session.request( diff --git a/tests/changeset_test.py b/tests/changeset_test.py index b11973a..fc5aecc 100644 --- a/tests/changeset_test.py +++ b/tests/changeset_test.py @@ -480,7 +480,9 @@ def test_ChangesetUpload_no_auth(api): with pytest.raises(osmapi.UsernamePasswordMissingError) as execinfo: api.ChangesetUpload(changesdata) - assert str(execinfo.value) == "Username/Password missing" + assert ( + str(execinfo.value) == "No username/password or 'Authorization' header provided" + ) def test_ChangesetDownload(api, add_response): @@ -677,7 +679,9 @@ def test_ChangesetComment(auth_api, add_response): def test_ChangesetComment_no_auth(api): with pytest.raises(osmapi.UsernamePasswordMissingError) as execinfo: api.ChangesetComment(123, comment="test comment") - assert str(execinfo.value) == "Username/Password missing" + assert ( + str(execinfo.value) == "No username/password or 'Authorization' header provided" + ) def test_ChangesetSubscribe(auth_api, add_response): @@ -717,7 +721,9 @@ def test_ChangesetSubscribeWhenAlreadySubscribed(auth_api, add_response): def test_ChangesetSubscribe_no_auth(api): with pytest.raises(osmapi.UsernamePasswordMissingError) as execinfo: api.ChangesetSubscribe(45627) - assert str(execinfo.value) == "Username/Password missing" + assert ( + str(execinfo.value) == "No username/password or 'Authorization' header provided" + ) def test_ChangesetUnsubscribe(auth_api, add_response): @@ -757,4 +763,6 @@ def test_ChangesetUnsubscribeWhenNotSubscribed(auth_api, add_response): def test_ChangesetUnsubscribe_no_auth(api): with pytest.raises(osmapi.UsernamePasswordMissingError) as execinfo: api.ChangesetUnsubscribe(45627) - assert str(execinfo.value) == "Username/Password missing" + assert ( + str(execinfo.value) == "No username/password or 'Authorization' header provided" + ) diff --git a/tests/node_test.py b/tests/node_test.py index 10e82b0..288b936 100644 --- a/tests/node_test.py +++ b/tests/node_test.py @@ -143,8 +143,6 @@ def test_NodeCreate_existing_node(self): self.api.NodeCreate(test_node) def test_NodeCreate_wo_auth(self): - self._session_mock() - # setup mock self.api.ChangesetCreate = mock.Mock(return_value=1111) self.api._CurrentChangesetId = 1111 @@ -155,7 +153,8 @@ def test_NodeCreate_wo_auth(self): } with self.assertRaisesRegex( - osmapi.UsernamePasswordMissingError, "Username/Password missing" + osmapi.UsernamePasswordMissingError, + "No username/password or 'Authorization' header provided", ): self.api.NodeCreate(test_node) From c63b41a0373a1a0bd46a6bab026dda931374ad49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Gy=C3=B6ngy=C3=B6si?= Date: Thu, 19 Feb 2026 08:53:13 +0100 Subject: [PATCH 2/4] Tests: reintroduce a fixed session mock That has a 'None' Authorization header instead of a unittest.mock.Mock object. Fixes https://github.com/metaodi/osmapi/pull/185#discussion_r2818694408. --- tests/node_test.py | 2 ++ tests/osmapi_test.py | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/node_test.py b/tests/node_test.py index 288b936..2f40a9e 100644 --- a/tests/node_test.py +++ b/tests/node_test.py @@ -143,6 +143,8 @@ def test_NodeCreate_existing_node(self): self.api.NodeCreate(test_node) def test_NodeCreate_wo_auth(self): + self._session_mock() + # setup mock self.api.ChangesetCreate = mock.Mock(return_value=1111) self.api._CurrentChangesetId = 1111 diff --git a/tests/osmapi_test.py b/tests/osmapi_test.py index 0515c0e..f1f9e0c 100644 --- a/tests/osmapi_test.py +++ b/tests/osmapi_test.py @@ -28,6 +28,7 @@ def _session_mock(self, auth=False, filenames=None, status=200): self.session_mock = mock.Mock() self.session_mock.request = mock.Mock(return_value=response_mock) self.session_mock.auth = None + self.session_mock.headers = {"Authorization": None} if auth: self.api = OsmApi( From 0ddfffd3787790c7582b6769b824dd288a2ef109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Gy=C3=B6ngy=C3=B6si?= Date: Sun, 8 Mar 2026 23:06:32 +0100 Subject: [PATCH 3/4] Update docstring of OsmApiSession._http_request() with new behavior Fixes https://github.com/metaodi/osmapi/pull/185#discussion_r2818694457. --- osmapi/http.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osmapi/http.py b/osmapi/http.py index 8814157..cd44b71 100644 --- a/osmapi/http.py +++ b/osmapi/http.py @@ -49,7 +49,8 @@ def _http_request(self, method, path, auth, send, return_value=True): # noqa `return_value` indicates wheter this request should return any data or not. - If the username or password is missing, + If the username or password is missing + and no Authorization header is present, `OsmApi.UsernamePasswordMissingError` is raised. If the requested element has been deleted, From 95c10cbee820f6b1a99e39f8a4f14582158455a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Gy=C3=B6ngy=C3=B6si?= Date: Sun, 8 Mar 2026 23:22:32 +0100 Subject: [PATCH 4/4] Add new test covering Bearer token authorization Fixes https://github.com/metaodi/osmapi/pull/185#discussion_r2818694437. --- tests/changeset_test.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/changeset_test.py b/tests/changeset_test.py index fc5aecc..417757d 100644 --- a/tests/changeset_test.py +++ b/tests/changeset_test.py @@ -676,6 +676,27 @@ def test_ChangesetComment(auth_api, add_response): } +def test_changeset_comment_with_session_authorization_header(add_response): + resp = add_response( + POST, + "/changeset/123/comment", + filename="test_ChangesetComment.xml", + ) + + session = requests.Session() + session.headers.update({"Authorization": "Bearer test-token"}) + api = osmapi.OsmApi(api="http://api06.dev.openstreetmap.org", session=session) + + try: + result = api.ChangesetComment(123, comment="test comment") + finally: + api.close() + + assert len(resp.calls) == 1 + assert resp.calls[0].request.body == "text=test+comment" + assert result["id"] == 123 + + def test_ChangesetComment_no_auth(api): with pytest.raises(osmapi.UsernamePasswordMissingError) as execinfo: api.ChangesetComment(123, comment="test comment")