Skip to content

Commit 3969dca

Browse files
authored
Merge pull request #65 from BillFarber/develop
Fixes the bug identified in https://progresssoftware.atlassian.net/browse/MLE-14411
2 parents 6461e72 + f475498 commit 3969dca

File tree

8 files changed

+92
-15
lines changed

8 files changed

+92
-15
lines changed

CONTRIBUTING.md

+12
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ project's documentation:
7676

7777
python -i shell/docs.py
7878

79+
80+
## Testing updates in a different local project
81+
If you are using this in another project and making changes for it, use the following command to make the
82+
changes to this local project immediately reflected in a dependent project:
83+
```poetry add <local-path-to-this-project>/marklogic-python-client/```
84+
85+
Using this method will allow you to very easily test changes to this project, in a different local project.
86+
87+
Keep in mind that you probably do not want to check that version of the pyproject.toml file into version
88+
control since it is only useful locally.
89+
90+
7991
## Testing the documentation locally
8092

8193
The docs for this project are stored in the `./docs` directory as a set of Markdown files. These are published via

marklogic/documents.py

+20-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
from collections import OrderedDict
3+
from email.message import Message
34
from typing import Union
45

56
from marklogic.transactions import Transaction
@@ -262,23 +263,29 @@ def _extract_values_from_header(part) -> dict:
262263
Returns a dict containing values about the document content or metadata.
263264
"""
264265
encoding = part.encoding
265-
disposition = part.headers["Content-Disposition".encode(encoding)].decode(encoding)
266-
disposition_values = {}
267-
for item in disposition.split(";"):
268-
tokens = item.split("=")
269-
# The first item will be "attachment" and can be ignored.
270-
if len(tokens) == 2:
271-
disposition_values[tokens[0].strip()] = tokens[1]
266+
disposition = part.headers["Content-Disposition".encode(encoding)].decode(
267+
encoding
268+
)
272269

273270
content_type = None
274271
if part.headers.get("Content-Type".encode(encoding)):
275-
content_type = part.headers["Content-Type".encode(encoding)].decode(encoding)
272+
content_type = part.headers["Content-Type".encode(encoding)].decode(
273+
encoding
274+
)
276275

277-
uri = disposition_values["filename"]
278-
if uri.startswith('"'):
279-
uri = uri[1:]
280-
if uri.endswith('"'):
281-
uri = uri[:-1]
276+
content_disposition_header = part.headers[
277+
"Content-Disposition".encode(encoding)
278+
].decode(encoding)
279+
msg = Message()
280+
msg["content-disposition"] = content_disposition_header
281+
uri = msg.get_filename()
282+
283+
disposition_values = {}
284+
for item in disposition.replace(uri, "").split(";"):
285+
tokens = item.split("=")
286+
key = tokens[0].strip()
287+
if key in ["category", "versionId"]:
288+
disposition_values[key] = tokens[1]
282289

283290
return {
284291
"uri": uri,

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "marklogic-python-client"
3-
version = "1.1.0"
3+
version = "1.1.1"
44
description = "Python client for MarkLogic, built on the requests library"
55
authors = ["MarkLogic <[email protected]>"]
66
readme = "README.md"

test-app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.gradle
22
gradle-local.properties
33
build
4+
docker

test-app/docker-compose.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: '3.8'
2+
name: marklogic_python
3+
4+
services:
5+
6+
marklogic:
7+
image: "marklogicdb/marklogic-db:11.2.0-centos-1.1.2"
8+
platform: linux/amd64
9+
environment:
10+
- INSTALL_CONVERTERS=true
11+
- MARKLOGIC_INIT=true
12+
- MARKLOGIC_ADMIN_USERNAME=admin
13+
- MARKLOGIC_ADMIN_PASSWORD=admin
14+
volumes:
15+
- ./docker/marklogic/logs:/var/opt/MarkLogic/Logs
16+
ports:
17+
- "8000-8002:8000-8002"
18+
- "8030-8031:8030-8031"
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<hello>semicolon</hello>
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<hello>equal</hello>

tests/test_search_docs.py

+38-1
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,11 @@ def test_search_with_original_response(client: Client):
8484

8585

8686
def test_collection(client: Client):
87+
8788
docs = client.documents.search(
8889
categories=["content", "collections"], collections=["search-test"]
8990
)
90-
assert len(docs) == 2
91+
assert len(docs) == 4
9192

9293
doc1 = next(doc for doc in docs if doc.uri == "/doc1.json")
9394
assert doc1.content is not None
@@ -101,6 +102,18 @@ def test_collection(client: Client):
101102
assert "test-data" in doc1.collections
102103
assert "search-test" in doc1.collections
103104

105+
doc3 = next(doc for doc in docs if doc.uri == "/doc2;copy.xml")
106+
assert doc3.content is not None
107+
assert len(doc3.collections) == 2
108+
assert "test-data" in doc3.collections
109+
assert "search-test" in doc3.collections
110+
111+
doc4 = next(doc for doc in docs if doc.uri == "/doc2=copy.xml")
112+
assert doc4.content is not None
113+
assert len(doc4.collections) == 2
114+
assert "test-data" in doc4.collections
115+
assert "search-test" in doc4.collections
116+
104117

105118
def test_not_rest_user(not_rest_user_client: Client):
106119
response: Response = not_rest_user_client.documents.search(q="hello")
@@ -109,3 +122,27 @@ def test_not_rest_user(not_rest_user_client: Client):
109122
), """The user does not have the rest-reader privilege, so MarkLogic is expected
110123
to return a 403. And the documents.search method is then expected to return the
111124
Response so that the user has access to everything in it."""
125+
126+
127+
def test_version_id(client: Client):
128+
equalSignEtag = (
129+
client.get("v1/documents?uri=/doc2=copy.xml")
130+
.headers["ETag"]
131+
.replace('"', "")
132+
)
133+
134+
semicolonEtag = (
135+
client.get("v1/documents?uri=/doc2;copy.xml")
136+
.headers["ETag"]
137+
.replace('"', "")
138+
)
139+
140+
docs = client.documents.search(
141+
categories=["content", "collections"], collections=["search-test"]
142+
)
143+
144+
doc1 = next(doc for doc in docs if doc.uri == "/doc2=copy.xml")
145+
assert doc1.version_id == equalSignEtag
146+
147+
doc2 = next(doc for doc in docs if doc.uri == "/doc2;copy.xml")
148+
assert doc2.version_id == semicolonEtag

0 commit comments

Comments
 (0)