diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e5880a3..4e4f1b5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,6 +76,18 @@ project's documentation: python -i shell/docs.py + +## Testing updates in a different local project +If you are using this in another project and making changes for it, use the following command to make the +changes to this local project immediately reflected in a dependent project: +```poetry add /marklogic-python-client/``` + +Using this method will allow you to very easily test changes to this project, in a different local project. + +Keep in mind that you probably do not want to check that version of the pyproject.toml file into version +control since it is only useful locally. + + ## Testing the documentation locally The docs for this project are stored in the `./docs` directory as a set of Markdown files. These are published via diff --git a/marklogic/documents.py b/marklogic/documents.py index 945f97f..ea6aa71 100644 --- a/marklogic/documents.py +++ b/marklogic/documents.py @@ -1,5 +1,6 @@ import json from collections import OrderedDict +from email.message import Message from typing import Union from marklogic.transactions import Transaction @@ -262,23 +263,29 @@ def _extract_values_from_header(part) -> dict: Returns a dict containing values about the document content or metadata. """ encoding = part.encoding - disposition = part.headers["Content-Disposition".encode(encoding)].decode(encoding) - disposition_values = {} - for item in disposition.split(";"): - tokens = item.split("=") - # The first item will be "attachment" and can be ignored. - if len(tokens) == 2: - disposition_values[tokens[0].strip()] = tokens[1] + disposition = part.headers["Content-Disposition".encode(encoding)].decode( + encoding + ) content_type = None if part.headers.get("Content-Type".encode(encoding)): - content_type = part.headers["Content-Type".encode(encoding)].decode(encoding) + content_type = part.headers["Content-Type".encode(encoding)].decode( + encoding + ) - uri = disposition_values["filename"] - if uri.startswith('"'): - uri = uri[1:] - if uri.endswith('"'): - uri = uri[:-1] + content_disposition_header = part.headers[ + "Content-Disposition".encode(encoding) + ].decode(encoding) + msg = Message() + msg["content-disposition"] = content_disposition_header + uri = msg.get_filename() + + disposition_values = {} + for item in disposition.replace(uri, "").split(";"): + tokens = item.split("=") + key = tokens[0].strip() + if key in ["category", "versionId"]: + disposition_values[key] = tokens[1] return { "uri": uri, diff --git a/pyproject.toml b/pyproject.toml index 1c5b2d9..1db4b73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "marklogic-python-client" -version = "1.1.0" +version = "1.1.1" description = "Python client for MarkLogic, built on the requests library" authors = ["MarkLogic "] readme = "README.md" diff --git a/test-app/.gitignore b/test-app/.gitignore index 3efdcd5..fb99400 100644 --- a/test-app/.gitignore +++ b/test-app/.gitignore @@ -1,3 +1,4 @@ .gradle gradle-local.properties build +docker \ No newline at end of file diff --git a/test-app/docker-compose.yml b/test-app/docker-compose.yml new file mode 100644 index 0000000..77703a1 --- /dev/null +++ b/test-app/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3.8' +name: marklogic_python + +services: + + marklogic: + image: "marklogicdb/marklogic-db:11.2.0-centos-1.1.2" + platform: linux/amd64 + environment: + - INSTALL_CONVERTERS=true + - MARKLOGIC_INIT=true + - MARKLOGIC_ADMIN_USERNAME=admin + - MARKLOGIC_ADMIN_PASSWORD=admin + volumes: + - ./docker/marklogic/logs:/var/opt/MarkLogic/Logs + ports: + - "8000-8002:8000-8002" + - "8030-8031:8030-8031" diff --git a/test-app/src/main/ml-data/doc2;copy.xml b/test-app/src/main/ml-data/doc2;copy.xml new file mode 100644 index 0000000..b234976 --- /dev/null +++ b/test-app/src/main/ml-data/doc2;copy.xml @@ -0,0 +1 @@ +semicolon \ No newline at end of file diff --git a/test-app/src/main/ml-data/doc2=copy.xml b/test-app/src/main/ml-data/doc2=copy.xml new file mode 100644 index 0000000..db3647b --- /dev/null +++ b/test-app/src/main/ml-data/doc2=copy.xml @@ -0,0 +1 @@ +equal \ No newline at end of file diff --git a/tests/test_search_docs.py b/tests/test_search_docs.py index cb8bdee..b549d3e 100644 --- a/tests/test_search_docs.py +++ b/tests/test_search_docs.py @@ -84,10 +84,11 @@ def test_search_with_original_response(client: Client): def test_collection(client: Client): + docs = client.documents.search( categories=["content", "collections"], collections=["search-test"] ) - assert len(docs) == 2 + assert len(docs) == 4 doc1 = next(doc for doc in docs if doc.uri == "/doc1.json") assert doc1.content is not None @@ -101,6 +102,18 @@ def test_collection(client: Client): assert "test-data" in doc1.collections assert "search-test" in doc1.collections + doc3 = next(doc for doc in docs if doc.uri == "/doc2;copy.xml") + assert doc3.content is not None + assert len(doc3.collections) == 2 + assert "test-data" in doc3.collections + assert "search-test" in doc3.collections + + doc4 = next(doc for doc in docs if doc.uri == "/doc2=copy.xml") + assert doc4.content is not None + assert len(doc4.collections) == 2 + assert "test-data" in doc4.collections + assert "search-test" in doc4.collections + def test_not_rest_user(not_rest_user_client: Client): response: Response = not_rest_user_client.documents.search(q="hello") @@ -109,3 +122,27 @@ def test_not_rest_user(not_rest_user_client: Client): ), """The user does not have the rest-reader privilege, so MarkLogic is expected to return a 403. And the documents.search method is then expected to return the Response so that the user has access to everything in it.""" + + +def test_version_id(client: Client): + equalSignEtag = ( + client.get("v1/documents?uri=/doc2=copy.xml") + .headers["ETag"] + .replace('"', "") + ) + + semicolonEtag = ( + client.get("v1/documents?uri=/doc2;copy.xml") + .headers["ETag"] + .replace('"', "") + ) + + docs = client.documents.search( + categories=["content", "collections"], collections=["search-test"] + ) + + doc1 = next(doc for doc in docs if doc.uri == "/doc2=copy.xml") + assert doc1.version_id == equalSignEtag + + doc2 = next(doc for doc in docs if doc.uri == "/doc2;copy.xml") + assert doc2.version_id == semicolonEtag