ds-caselaw-marklogic-api-client 29.1.1__py3-none-any.whl → 29.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ds-caselaw-marklogic-api-client might be problematic. Click here for more details.

@@ -29,7 +29,6 @@ from caselawclient.models.utilities.aws import (
29
29
  publish_documents,
30
30
  request_parse,
31
31
  unpublish_documents,
32
- uri_for_s3,
33
32
  )
34
33
 
35
34
  from .body import DocumentBody
@@ -216,11 +215,11 @@ class Document:
216
215
 
217
216
  @property
218
217
  def docx_url(self) -> str:
219
- return generate_docx_url(uri_for_s3(self.uri))
218
+ return generate_docx_url(self.uri)
220
219
 
221
220
  @property
222
221
  def pdf_url(self) -> str:
223
- return generate_pdf_url(uri_for_s3(self.uri))
222
+ return generate_pdf_url(self.uri)
224
223
 
225
224
  @cached_property
226
225
  def assigned_to(self) -> str:
@@ -438,7 +437,7 @@ class Document:
438
437
  self.identifiers.add(document_fclid)
439
438
  self.save_identifiers()
440
439
 
441
- publish_documents(uri_for_s3(self.uri))
440
+ publish_documents(self.uri)
442
441
  self.api_client.set_published(self.uri, True)
443
442
  announce_document_event(
444
443
  uri=self.uri,
@@ -448,7 +447,7 @@ class Document:
448
447
 
449
448
  def unpublish(self) -> None:
450
449
  self.api_client.break_checkout(self.uri)
451
- unpublish_documents(uri_for_s3(self.uri))
450
+ unpublish_documents(self.uri)
452
451
  self.api_client.set_published(self.uri, False)
453
452
  announce_document_event(
454
453
  uri=self.uri,
@@ -23,11 +23,6 @@ class NeutralCitationMixin(ABC):
23
23
 
24
24
  def __init__(self, document_noun: str, *args: Any, **kwargs: Any) -> None:
25
25
  self.attributes_to_validate: list[tuple[str, bool, str]] = self.attributes_to_validate + [
26
- (
27
- "has_ncn",
28
- True,
29
- f"This {document_noun} has no neutral citation number",
30
- ),
31
26
  (
32
27
  "has_valid_ncn",
33
28
  True,
@@ -50,4 +45,6 @@ class NeutralCitationMixin(ABC):
50
45
  @cached_property
51
46
  @deprecated("Legacy usage of NCNs is deprecated; you should be moving to the Identifiers framework")
52
47
  def has_valid_ncn(self) -> bool:
53
- return self.neutral_citation is not None and neutral_url(self.neutral_citation) is not None
48
+ if self.neutral_citation is None:
49
+ return True
50
+ return neutral_url(self.neutral_citation) is not None
@@ -2,7 +2,7 @@ import datetime
2
2
  import json
3
3
  import logging
4
4
  import uuid
5
- from typing import Any, Literal, Optional, TypedDict, overload
5
+ from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict, overload
6
6
 
7
7
  import boto3
8
8
  import botocore.client
@@ -13,9 +13,21 @@ from mypy_boto3_sns.client import SNSClient
13
13
  from mypy_boto3_sns.type_defs import MessageAttributeValueTypeDef
14
14
  from typing_extensions import NotRequired
15
15
 
16
+ if TYPE_CHECKING:
17
+ from caselawclient.models.documents import DocumentURIString
18
+ else:
19
+ DocumentURIString = None
20
+
16
21
  env = environ.Env()
17
22
 
18
23
 
24
+ class S3PrefixString(str):
25
+ def __new__(cls, content: str) -> "S3PrefixString":
26
+ if content[-1] != "/":
27
+ raise RuntimeError("S3 Prefixes must end in / so they behave like directories")
28
+ return str.__new__(cls, content)
29
+
30
+
19
31
  class ParserInstructionsMetadataDict(TypedDict):
20
32
  name: Optional[str]
21
33
  cite: Optional[str]
@@ -58,8 +70,9 @@ def create_sns_client() -> SNSClient:
58
70
  return create_aws_client("sns")
59
71
 
60
72
 
61
- def uri_for_s3(uri: str) -> str:
62
- return uri.lstrip("/")
73
+ def uri_for_s3(uri: DocumentURIString) -> S3PrefixString:
74
+ """An S3 Prefix must end with / to avoid uksc/2004/1 matching uksc/2004/1000"""
75
+ return S3PrefixString(uri + "/")
63
76
 
64
77
 
65
78
  def generate_signed_asset_url(key: str) -> str:
@@ -79,7 +92,7 @@ def generate_signed_asset_url(key: str) -> str:
79
92
  )
80
93
 
81
94
 
82
- def check_docx_exists(uri: str) -> bool:
95
+ def check_docx_exists(uri: DocumentURIString) -> bool:
83
96
  """Does the docx for a document URI actually exist?"""
84
97
  bucket = env("PRIVATE_ASSET_BUCKET", None)
85
98
  s3_key = generate_docx_key(uri)
@@ -93,25 +106,25 @@ def check_docx_exists(uri: str) -> bool:
93
106
  raise
94
107
 
95
108
 
96
- def generate_docx_key(uri: str) -> str:
109
+ def generate_docx_key(uri: DocumentURIString) -> str:
97
110
  """from a canonical caselaw URI (eat/2022/1) return the S3 key of the associated docx"""
98
111
  return f"{uri}/{uri.replace('/', '_')}.docx"
99
112
 
100
113
 
101
- def generate_docx_url(uri: str) -> str:
114
+ def generate_docx_url(uri: DocumentURIString) -> str:
102
115
  """from a canonical caselaw URI (eat/2022/1) return a signed S3 link for the front end"""
103
116
  return generate_signed_asset_url(generate_docx_key(uri))
104
117
 
105
118
 
106
- def generate_pdf_url(uri: str) -> str:
119
+ def generate_pdf_url(uri: DocumentURIString) -> str:
107
120
  key = f"{uri}/{uri.replace('/', '_')}.pdf"
108
121
 
109
122
  return generate_signed_asset_url(key)
110
123
 
111
124
 
112
- def delete_from_bucket(uri: str, bucket: str) -> None:
125
+ def delete_from_bucket(uri: DocumentURIString, bucket: str) -> None:
113
126
  client = create_s3_client()
114
- response = client.list_objects(Bucket=bucket, Prefix=uri)
127
+ response = client.list_objects(Bucket=bucket, Prefix=uri_for_s3(uri))
115
128
 
116
129
  if response.get("Contents"):
117
130
  objects_to_delete: list[ObjectIdentifierTypeDef] = [{"Key": obj["Key"]} for obj in response.get("Contents", [])]
@@ -123,7 +136,7 @@ def delete_from_bucket(uri: str, bucket: str) -> None:
123
136
  )
124
137
 
125
138
 
126
- def publish_documents(uri: str) -> None:
139
+ def publish_documents(uri: DocumentURIString) -> None:
127
140
  """
128
141
  Copy assets from the unpublished bucket to the published one.
129
142
  Don't copy parser logs and package tar gz.
@@ -134,7 +147,7 @@ def publish_documents(uri: str) -> None:
134
147
  public_bucket = env("PUBLIC_ASSET_BUCKET")
135
148
  private_bucket = env("PRIVATE_ASSET_BUCKET")
136
149
 
137
- response = client.list_objects(Bucket=private_bucket, Prefix=uri)
150
+ response = client.list_objects(Bucket=private_bucket, Prefix=uri_for_s3(uri))
138
151
 
139
152
  for result in response.get("Contents", []):
140
153
  print(f"Contemplating copying {result!r}")
@@ -152,15 +165,15 @@ def publish_documents(uri: str) -> None:
152
165
  )
153
166
 
154
167
 
155
- def unpublish_documents(uri: str) -> None:
168
+ def unpublish_documents(uri: DocumentURIString) -> None:
156
169
  delete_from_bucket(uri, env("PUBLIC_ASSET_BUCKET"))
157
170
 
158
171
 
159
- def delete_documents_from_private_bucket(uri: str) -> None:
172
+ def delete_documents_from_private_bucket(uri: DocumentURIString) -> None:
160
173
  delete_from_bucket(uri, env("PRIVATE_ASSET_BUCKET"))
161
174
 
162
175
 
163
- def announce_document_event(uri: str, status: str, enrich: bool = False) -> None:
176
+ def announce_document_event(uri: DocumentURIString, status: str, enrich: bool = False) -> None:
164
177
  client = create_sns_client()
165
178
 
166
179
  message_attributes: dict[str, MessageAttributeValueTypeDef] = {}
@@ -186,17 +199,14 @@ def announce_document_event(uri: str, status: str, enrich: bool = False) -> None
186
199
  )
187
200
 
188
201
 
189
- def copy_assets(old_uri: str, new_uri: str) -> None:
202
+ def copy_assets(old_uri: DocumentURIString, new_uri: DocumentURIString) -> None:
190
203
  """
191
204
  Copy *unpublished* assets from one path to another,
192
205
  renaming DOCX and PDF files as appropriate.
193
206
  """
194
207
  client = create_s3_client()
195
208
  bucket = env("PRIVATE_ASSET_BUCKET")
196
- old_uri = uri_for_s3(old_uri)
197
- new_uri = uri_for_s3(new_uri)
198
-
199
- response = client.list_objects(Bucket=bucket, Prefix=old_uri)
209
+ response = client.list_objects(Bucket=bucket, Prefix=uri_for_s3(old_uri))
200
210
 
201
211
  for result in response.get("Contents", []):
202
212
  old_key = str(result["Key"])
@@ -212,7 +222,7 @@ def copy_assets(old_uri: str, new_uri: str) -> None:
212
222
  )
213
223
 
214
224
 
215
- def build_new_key(old_key: str, new_uri: str) -> str:
225
+ def build_new_key(old_key: str, new_uri: DocumentURIString) -> str:
216
226
  """Ensure that DOCX and PDF filenames are modified to reflect their new home
217
227
  as we get the name of the new S3 path"""
218
228
  old_filename = old_key.rsplit("/", 1)[-1]
@@ -224,7 +234,7 @@ def build_new_key(old_key: str, new_uri: str) -> str:
224
234
 
225
235
 
226
236
  def request_parse(
227
- uri: str,
237
+ uri: DocumentURIString,
228
238
  reference: Optional[str],
229
239
  parser_instructions: Optional[ParserInstructionsDict] = None,
230
240
  ) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ds-caselaw-marklogic-api-client
3
- Version: 29.1.1
3
+ Version: 29.2.0
4
4
  Summary: An API client for interacting with the underlying data in Find Caselaw.
5
5
  Home-page: https://github.com/nationalarchives/ds-caselaw-custom-api-client
6
6
  Keywords: national archives,caselaw
@@ -7,7 +7,7 @@ caselawclient/errors.py,sha256=JC16fEGq_MRJX-_KFzfINCV2Cqx8o6OWOt3C16rQd84,3142
7
7
  caselawclient/factories.py,sha256=6-xZMVmvtXA8AnyWJgJTums1EWfM6lPIhrWQu0NopJo,4472
8
8
  caselawclient/identifier_resolution.py,sha256=IOqrZcIHoHhNOCAkNveOBcWddBNpkOB8cz1r0zFa8mQ,1829
9
9
  caselawclient/models/__init__.py,sha256=kd23EUpvaC7aLHdgk8farqKAQEx3lf7RvNT2jEatvlg,68
10
- caselawclient/models/documents/__init__.py,sha256=Lzb18MyCPLlG0Y4EdnjZvnGFSSpsNs_BUgJA6BQqL28,19520
10
+ caselawclient/models/documents/__init__.py,sha256=huZ-aQ-tsfuWScqSPkBAAQ9dhYa98fdd5eHwO85s_BQ,19456
11
11
  caselawclient/models/documents/body.py,sha256=7Sj6lnddcAM8VAeecAS2VEhQHR9CB3G0fL8TAXz7EXw,5588
12
12
  caselawclient/models/documents/exceptions.py,sha256=rw1xId16vBKvBImgFmFUpeFgKqU7VTNtVLIEVBPGKyk,374
13
13
  caselawclient/models/documents/statuses.py,sha256=Cp4dTQmJOtsU41EJcxy5dV1841pGD2PNWH0VrkDEv4Q,579
@@ -19,10 +19,10 @@ caselawclient/models/identifiers/neutral_citation.py,sha256=3Jw1_-NmGfGmrWGFSzLd
19
19
  caselawclient/models/identifiers/press_summary_ncn.py,sha256=r55-qgi9LDnGxY8vTKijzotGknA6mNLpu55QQTV8Lxo,652
20
20
  caselawclient/models/identifiers/unpacker.py,sha256=xvp480QESbN36NEc6qeo-orqOBq6WchnLI7thY7A1qs,2156
21
21
  caselawclient/models/judgments.py,sha256=xFjfOspa9ZL29gvvGVNq11JC7h-LKebFMrQYvVIIoEI,1868
22
- caselawclient/models/neutral_citation_mixin.py,sha256=LDaxNndLcTKsjJCyEKO1kGTJ6YD6h-6SzQVE0-gwPSI,2208
22
+ caselawclient/models/neutral_citation_mixin.py,sha256=jAac3PPuWyPdj9N-n-U_JfwkbgbSIXaqFVQahfu95do,2086
23
23
  caselawclient/models/press_summaries.py,sha256=bEqJxu-7eBLhwulOsDXYDl2ptIp3RkkMpOcdVvWB5ds,1836
24
24
  caselawclient/models/utilities/__init__.py,sha256=u3yIhbTjFQ1JJyAm5wsMEBswWl4t6Z7UMORF5FqC2xQ,1257
25
- caselawclient/models/utilities/aws.py,sha256=d-7puHSW8lFLLhaXhAStzNai4_NEMAiPGCNEFUt0Elg,8191
25
+ caselawclient/models/utilities/aws.py,sha256=5UJhxdGwYwH0bswi3q9nzmXcioPz9t_lNWYmP45RyK4,8842
26
26
  caselawclient/models/utilities/dates.py,sha256=WwORxVjUHM1ZFcBF6Qtwo3Cj0sATsnSECkUZ6ls1N1Q,492
27
27
  caselawclient/models/utilities/move.py,sha256=Rsx1eGHVjbGz0WMVDjy8b_5t4Ig8aP55sLudL07MVUs,3621
28
28
  caselawclient/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -78,7 +78,7 @@ caselawclient/xquery/validate_document.xqy,sha256=PgaDcnqCRJPIVqfmWsNlXmCLNKd21q
78
78
  caselawclient/xquery/xslt.xqy,sha256=w57wNijH3dkwHkpKeAxqjlghVflQwo8cq6jS_sm-erM,199
79
79
  caselawclient/xquery/xslt_transform.xqy,sha256=smyFFxqmtkuOzBd2l7uw6K2oAsYctudrP8omdv_XNAM,2463
80
80
  caselawclient/xquery_type_dicts.py,sha256=kybL-YzwK34Fr6MeWfqVOJHYrs0ZNeDWXDsp8o2Yb1U,6114
81
- ds_caselaw_marklogic_api_client-29.1.1.dist-info/LICENSE.md,sha256=fGMzyyLuQW-IAXUeDSCrRdsYW536aEWThdbpCjo6ZKg,1108
82
- ds_caselaw_marklogic_api_client-29.1.1.dist-info/METADATA,sha256=SaMj0ydb-vZeW6cnwnwr94lGc_XkADBIDeUdWtDlEjM,4264
83
- ds_caselaw_marklogic_api_client-29.1.1.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
84
- ds_caselaw_marklogic_api_client-29.1.1.dist-info/RECORD,,
81
+ ds_caselaw_marklogic_api_client-29.2.0.dist-info/LICENSE.md,sha256=fGMzyyLuQW-IAXUeDSCrRdsYW536aEWThdbpCjo6ZKg,1108
82
+ ds_caselaw_marklogic_api_client-29.2.0.dist-info/METADATA,sha256=ALbG5q-13rqmY9R-1lUB7LLUnZppeBT4A9xssTV5skM,4264
83
+ ds_caselaw_marklogic_api_client-29.2.0.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
84
+ ds_caselaw_marklogic_api_client-29.2.0.dist-info/RECORD,,