From 5f9338e7e9d4c49df1cd9a14b946fccf8afded2d Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 11:35:04 -0300 Subject: [PATCH 01/10] Namespace changes --- couchapy/database.py | 11 ++--------- couchapy/private/changes.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 couchapy/private/changes.py diff --git a/couchapy/database.py b/couchapy/database.py index c135794..40d95b4 100644 --- a/couchapy/database.py +++ b/couchapy/database.py @@ -1,5 +1,6 @@ import couchapy.decorators as couch import couchapy.error +import couchapy.private.changes as _changes import couchapy.private.design as _design import couchapy.private.document as _docs import couchapy.private.local as _local @@ -17,6 +18,7 @@ def __init__(self, parent, **kwargs): self.design = _design._DesignDocument(self) self.local = _local._LocalDocuments(self) self.docs = _docs._Documents(self) + self.changes = _changes._DatabaseChanges(self) @couch.endpoint('/:db:', method='head') def headers(self, couch_data, **kwargs): @@ -150,12 +152,3 @@ def get_shard(self, couch_data, **kwargs): @couch.endpoint('/:db:/_sync_shards', method='post') def sync_shards(self, couch_data, **kwargs): return couch_data - - @couch.endpoint('/:db:/_changes', query_keys=couch.AllowedKeys.DATABASE__CHANGES__PARAMS) - def get_changes(self, couch_data, **kwargs): - return couch_data - - # TODO: make note in this doc string about the lack of data_keys since it supports query keys as well as find data keys - @couch.endpoint('/:db:/_changes', method='post', query_keys=couch.AllowedKeys.DATABASE__CHANGES__PARAMS) - def get_filtered_changes(self, couch_data, **kwargs): - return couch_data diff --git a/couchapy/private/changes.py b/couchapy/private/changes.py new file mode 100644 index 0000000..662a468 --- /dev/null +++ b/couchapy/private/changes.py @@ -0,0 +1,31 @@ +import couchapy.decorators as couch + + +class _DatabaseChanges(): + """ + Namespace class for design document related endpoints. + + This class is not intended for direct use and should be accessed through the database attribute of a CouchDB instance. + """ + def __init__(self, parent, **kwargs): + # TODO: rename this to reference the host couch instance + self.parent = parent.parent + self._db = parent._db + self._predefined_segments = parent._predefined_segments + + @couch.endpoint('/:db:/_changes', method='post', + data_keys=couch.AllowedKeys.DATABASE__CHANGES__DATA, + query_keys=couch.AllowedKeys.DATABASE__CHANGES__PARAMS) + def get_by_post(self, couch_data, **kwargs): + """ + See https://docs.couchdb.org/en/stable/api/database/bulk-api.html#post--db-_design_docs + """ + return couch_data + + @couch.endpoint('/:db:/_changes', query_keys=couch.AllowedKeys.DATABASE__CHANGES__PARAMS) + def get(self, couch_data, **kwargs): + """ + See https://docs.couchdb.org/en/stable/api/ddoc/common.html#get--db-_design-ddoc + See https://docs.couchdb.org/en/stable/api/document/common.html#get--db-docid + """ + return couch_data From 8434106122a07f8e9f155186cda1c663a4ffa97d Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 11:55:47 -0300 Subject: [PATCH 02/10] =?UTF-8?q?Bump=20version:=200.0.1-alpha.2=20?= =?UTF-8?q?=E2=86=92=200.0.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- couchapy/__init__.py | 6 ++++++ setup.cfg | 22 ++++++++++++++++++++++ setup.py | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 setup.cfg diff --git a/couchapy/__init__.py b/couchapy/__init__.py index 2301dd9..a6e05ce 100644 --- a/couchapy/__init__.py +++ b/couchapy/__init__.py @@ -1,3 +1,9 @@ +"""Top-level package for Flask Torusoft API Core.""" + from couchapy.couchdb import CouchDB from couchapy.error import CouchError, InvalidKeysException from couchapy.session import Session + +__author__ = """Lee Lunn""" +__email__ = 'lee@torusoft.com' +__version__ = '__version__ = '0.0.2'' diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..7a1c464 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,22 @@ +[bumpversion] +current_version = 0.0.2 +commit = True +tag = True + +[bumpversion:file:setup.py] +search = version='{current_version}' +replace = version='{new_version}' + +[bumpversion:file:couchapy/__init__.py] +search = __version__ = '{current_version}' +replace = __version__ = '{new_version}' + +[bdist_wheel] +universal = 1 + +[flake8] +exclude = docs + +[tool:pytest] +collect_ignore = ['setup.py'] + diff --git a/setup.py b/setup.py index aff285c..f258c3b 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="couchapy", - version="0.0.1-alpha.2", + version="version='0.0.2'", author="Lee Lunn", author_email="lee.lunn@gmail.com", description="Library for interacting with CouchDB", From 486853ad6cd89eef3f22ef83fb5bcf83db9482e8 Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 11:57:37 -0300 Subject: [PATCH 03/10] Fixes typo --- couchapy/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchapy/__init__.py b/couchapy/__init__.py index a6e05ce..db229f7 100644 --- a/couchapy/__init__.py +++ b/couchapy/__init__.py @@ -6,4 +6,4 @@ __author__ = """Lee Lunn""" __email__ = 'lee@torusoft.com' -__version__ = '__version__ = '0.0.2'' +__version__ = '__version__ = '0.0.2' From 30d0f1cebd0ec55966bc1dbdcc61f4a158a68e53 Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 12:00:14 -0300 Subject: [PATCH 04/10] Fix bump2version find and replace error --- couchapy/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchapy/__init__.py b/couchapy/__init__.py index db229f7..6fbc74e 100644 --- a/couchapy/__init__.py +++ b/couchapy/__init__.py @@ -6,4 +6,4 @@ __author__ = """Lee Lunn""" __email__ = 'lee@torusoft.com' -__version__ = '__version__ = '0.0.2' +__version__ = '0.0.2' From 88a1d38b326c67332492897162acd9646825e527 Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 12:02:01 -0300 Subject: [PATCH 05/10] Fix pytest scope error --- tests/conftest.py | 6 ++++++ tests/unit/test_couchdb.py | 5 ----- tests/unit/test_database.py | 5 ----- tests/unit/test_design.py | 5 ----- tests/unit/test_document.py | 5 ----- tests/unit/test_local.py | 5 ----- tests/unit/test_revisions.py | 5 ----- tests/unit/test_security.py | 5 ----- tests/unit/test_server.py | 5 ----- tests/unit/test_session.py | 5 ----- tests/unit/test_view.py | 3 --- 11 files changed, 6 insertions(+), 48 deletions(-) create mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..87e656a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,6 @@ +import pytest + + +@pytest.fixture(scope='session') +def httpserver_listen_address(): + return ("127.0.0.1", 8000) diff --git a/tests/unit/test_couchdb.py b/tests/unit/test_couchdb.py index cb952a2..5a10a22 100644 --- a/tests/unit/test_couchdb.py +++ b/tests/unit/test_couchdb.py @@ -6,11 +6,6 @@ import time -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_database.py b/tests/unit/test_database.py index 0ddbfed..96b2197 100644 --- a/tests/unit/test_database.py +++ b/tests/unit/test_database.py @@ -4,11 +4,6 @@ import pytest_httpserver as test_server -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_design.py b/tests/unit/test_design.py index c73fc09..49f3de1 100644 --- a/tests/unit/test_design.py +++ b/tests/unit/test_design.py @@ -5,11 +5,6 @@ from werkzeug.wrappers.response import Response -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_document.py b/tests/unit/test_document.py index c1bced9..e71fb59 100644 --- a/tests/unit/test_document.py +++ b/tests/unit/test_document.py @@ -5,11 +5,6 @@ from werkzeug.wrappers.response import Response -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_local.py b/tests/unit/test_local.py index 307cb89..ee75287 100644 --- a/tests/unit/test_local.py +++ b/tests/unit/test_local.py @@ -3,11 +3,6 @@ import pytest_httpserver as test_server -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_revisions.py b/tests/unit/test_revisions.py index 1b035f0..b3bf129 100644 --- a/tests/unit/test_revisions.py +++ b/tests/unit/test_revisions.py @@ -4,11 +4,6 @@ import pytest_httpserver as test_server -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_security.py b/tests/unit/test_security.py index d6b7816..26cffea 100644 --- a/tests/unit/test_security.py +++ b/tests/unit/test_security.py @@ -3,11 +3,6 @@ import pytest_httpserver as test_server -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_server.py b/tests/unit/test_server.py index 61e3c2d..53b8e16 100644 --- a/tests/unit/test_server.py +++ b/tests/unit/test_server.py @@ -4,11 +4,6 @@ import pytest_httpserver as test_server -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - @pytest.fixture(autouse=True) def setup(): """ setup any state specific to the execution of the given module.""" diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py index ba0f4af..1f4e45a 100644 --- a/tests/unit/test_session.py +++ b/tests/unit/test_session.py @@ -3,11 +3,6 @@ from pytest_httpserver import HTTPServer -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) - - def test_authenticate(httpserver: HTTPServer): json_response = {"ok": True, "name": "root", "roles": ["_admin"]} diff --git a/tests/unit/test_view.py b/tests/unit/test_view.py index 1650531..a800308 100644 --- a/tests/unit/test_view.py +++ b/tests/unit/test_view.py @@ -3,9 +3,6 @@ import pytest_httpserver as test_server -@pytest.fixture -def httpserver_listen_address(): - return ("127.0.0.1", 8000) @pytest.fixture(autouse=True) From 4cfecdf9155d837cf939b60e7ae3adaf14dcff00 Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 12:15:10 -0300 Subject: [PATCH 06/10] Fix tests --- tests/unit/test_database.py | 4 ++-- tests/unit/test_server.py | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/unit/test_database.py b/tests/unit/test_database.py index 96b2197..d8a9c44 100644 --- a/tests/unit/test_database.py +++ b/tests/unit/test_database.py @@ -108,12 +108,12 @@ def test_delete(httpserver: test_server.HTTPServer): for code in [202]: httpserver.expect_oneshot_request("/somedb", method="DELETE").respond_with_json({}, status=code) - response = couch.server.delete_database() + response = couch.server.delete_database(uri_segments={'db': 'somedb'}) assert isinstance(response, couchapy.CouchError) is False for code in [400, 401, 404, 500]: httpserver.expect_oneshot_request("/somedb", method="DELETE").respond_with_json({}, status=code) - response = couch.server.delete_database() + response = couch.server.delete_database(uri_segments={'db': 'somedb'}) assert isinstance(response, couchapy.CouchError) is True diff --git a/tests/unit/test_server.py b/tests/unit/test_server.py index 53b8e16..c8aa845 100644 --- a/tests/unit/test_server.py +++ b/tests/unit/test_server.py @@ -466,9 +466,6 @@ def test_get_node_server_stat(httpserver: test_server.HTTPServer): response = couch.server.node_stat(uri_segments={'node_name': '_local', 'stat': 'couchdb/request_time'}) assert response == expected_json - response = couch.server.node_stat() - assert response == expected_json - def test_get_node_system_stats(httpserver: test_server.HTTPServer): expected_json = {"uptime": 259, "memory": 1000} @@ -673,10 +670,10 @@ def test_database_delete(httpserver: test_server.HTTPServer): for code in [202]: httpserver.expect_oneshot_request("/somedb", method="DELETE").respond_with_json({}, status=code) - response = couch.server.delete_database() + response = couch.server.delete_database(uri_segments={'db': 'somedb'}) assert isinstance(response, couchapy.CouchError) is False for code in [400, 401, 404, 500]: httpserver.expect_oneshot_request("/somedb", method="DELETE").respond_with_json({}, status=code) - response = couch.server.delete_database() + response = couch.server.delete_database(uri_segments={'db': 'somedb'}) assert isinstance(response, couchapy.CouchError) is True From 50777871bd006049af1e4f531c0dec7b9ad6b2a3 Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 12:29:28 -0300 Subject: [PATCH 07/10] Expand test comparison for 3.7 troubleshooting --- tests/unit/test_document.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_document.py b/tests/unit/test_document.py index e71fb59..d9dca1b 100644 --- a/tests/unit/test_document.py +++ b/tests/unit/test_document.py @@ -201,7 +201,23 @@ def test_attachment_headers(httpserver: test_server.HTTPServer): httpserver.expect_request("/_local/doc_name/attachment", method="HEAD").respond_with_json({}, headers=expected) response = couch.db.docs.attachment.headers(uri_segments={'db': '_local', 'docid': 'doc_name', 'attname': 'attachment'}) - assert response == expected + + assert 'Accept-Ranges' in response + assert response['Accept-Ranges'] == expected['Accept-Ranges'] + assert 'Cache-Control' in response + assert response['Cache-Control'] == expected['Cache-Control'] + assert 'Content-Encoding' in response + assert response['Content-Encoding'] == expected['Content-Encoding'] + assert 'Content-Length' in response + assert response['Content-Length'] == expected['Content-Length'] + assert 'Content-Type' in response + assert response['Content-Type'] == expected['Content-Type'] + assert 'Date' in response + assert response['Date'] == expected['Date'] + assert 'ETag' in response + assert response['ETag'] == expected['ETag'] + assert 'Server' in response + assert response['Server'] == expected['Server'] def test_get_attachment(httpserver: test_server.HTTPServer): From 6a55fed2ca1b238d37f1fc310baecbdbf202042c Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 12:35:16 -0300 Subject: [PATCH 08/10] Remove date comparison assertion; not relevant. --- tests/unit/test_document.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/test_document.py b/tests/unit/test_document.py index d9dca1b..23e7476 100644 --- a/tests/unit/test_document.py +++ b/tests/unit/test_document.py @@ -213,7 +213,6 @@ def test_attachment_headers(httpserver: test_server.HTTPServer): assert 'Content-Type' in response assert response['Content-Type'] == expected['Content-Type'] assert 'Date' in response - assert response['Date'] == expected['Date'] assert 'ETag' in response assert response['ETag'] == expected['ETag'] assert 'Server' in response From bd7c2aa09a724dc440f7c188982d50b16a4f8610 Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 12:44:25 -0300 Subject: [PATCH 09/10] Remove assertion checks for dynamic values on http server headers --- tests/unit/test_database.py | 10 +++++++++- tests/unit/test_design.py | 11 ++++++++++- tests/unit/test_document.py | 12 ++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_database.py b/tests/unit/test_database.py index d8a9c44..7d9f776 100644 --- a/tests/unit/test_database.py +++ b/tests/unit/test_database.py @@ -34,7 +34,15 @@ def test_headers(httpserver: test_server.HTTPServer): httpserver.expect_request("/_local", method="HEAD").respond_with_json({}, headers=expected, status=404) response = couch.db.headers(uri_segments={'db': '_local'}) - assert response == expected + + assert 'Cache-Control' in response + assert response['Cache-Control'] == expected['Cache-Control'] + assert 'Content-Length' in response + assert response['Content-Length'] == expected['Content-Length'] + assert 'Content-Type' in response + assert response['Content-Type'] == expected['Content-Type'] + assert 'Date' in response + assert 'Server' in response def test_database_exists(httpserver: test_server.HTTPServer): diff --git a/tests/unit/test_design.py b/tests/unit/test_design.py index 49f3de1..699a290 100644 --- a/tests/unit/test_design.py +++ b/tests/unit/test_design.py @@ -130,7 +130,16 @@ def test_headers(httpserver: test_server.HTTPServer): httpserver.expect_request("/_local/_design/ddoc_name", method="HEAD").respond_with_json({}, headers=expected) response = couch.db.design.headers(uri_segments={'db': '_local', 'ddoc': 'ddoc_name'}) - assert response == expected + + assert 'Cache-Control' in response + assert response['Cache-Control'] == expected['Cache-Control'] + assert 'Content-Length' in response + assert response['Content-Length'] == expected['Content-Length'] + assert 'Content-Type' in response + assert response['Content-Type'] == expected['Content-Type'] + assert 'Date' in response + assert 'Server' in response + def test_info(httpserver: test_server.HTTPServer): diff --git a/tests/unit/test_document.py b/tests/unit/test_document.py index 23e7476..dffe3f4 100644 --- a/tests/unit/test_document.py +++ b/tests/unit/test_document.py @@ -35,7 +35,16 @@ def test_headers(httpserver: test_server.HTTPServer): httpserver.expect_request("/_local/doc_name", method="HEAD").respond_with_json({}, headers=expected) response = couch.db.docs.headers(uri_segments={'db': '_local', 'docid': 'doc_name'}) - assert response == expected + + assert 'Cache-Control' in response + assert response['Cache-Control'] == expected['Cache-Control'] + assert 'Content-Length' in response + assert response['Content-Length'] == expected['Content-Length'] + assert 'Content-Type' in response + assert response['Content-Type'] == expected['Content-Type'] + assert 'Date' in response + assert 'Server' in response + def test_queries(httpserver: test_server.HTTPServer): @@ -216,7 +225,6 @@ def test_attachment_headers(httpserver: test_server.HTTPServer): assert 'ETag' in response assert response['ETag'] == expected['ETag'] assert 'Server' in response - assert response['Server'] == expected['Server'] def test_get_attachment(httpserver: test_server.HTTPServer): From 2b18066aca8f4f9cce840e0b715959139c1f5ff1 Mon Sep 17 00:00:00 2001 From: Lee Lunn Date: Sat, 7 May 2022 12:46:12 -0300 Subject: [PATCH 10/10] More response assertion expansion on headers... --- tests/unit/test_design.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_design.py b/tests/unit/test_design.py index 699a290..3357361 100644 --- a/tests/unit/test_design.py +++ b/tests/unit/test_design.py @@ -181,7 +181,22 @@ def test_attachment_headers(httpserver: test_server.HTTPServer): httpserver.expect_request("/_local/_design/ddoc_name/attachment", method="HEAD").respond_with_json({}, headers=expected) response = couch.db.design.attachment.headers(uri_segments={'db': '_local', 'ddoc': 'ddoc_name', 'attname': 'attachment'}) - assert response == expected + + assert 'Accept-Ranges' in response + assert response['Accept-Ranges'] == expected['Accept-Ranges'] + assert 'Cache-Control' in response + assert response['Cache-Control'] == expected['Cache-Control'] + assert 'Content-Encoding' in response + assert response['Content-Encoding'] == expected['Content-Encoding'] + assert 'Content-Length' in response + assert response['Content-Length'] == expected['Content-Length'] + assert 'Content-Type' in response + assert response['Content-Type'] == expected['Content-Type'] + assert 'Date' in response + assert 'ETag' in response + assert response['ETag'] == expected['ETag'] + assert 'Server' in response + def test_get_attachment(httpserver: test_server.HTTPServer):