ds-caselaw-marklogic-api-client 39.0.0__tar.gz → 39.2.0__tar.gz

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.

Files changed (94) hide show
  1. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/PKG-INFO +7 -4
  2. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/README.md +3 -1
  3. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/pyproject.toml +13 -10
  4. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/Client.py +25 -14
  5. ds_caselaw_marklogic_api_client-39.2.0/src/caselawclient/__init__.py +63 -0
  6. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/documents/__init__.py +11 -3
  7. ds_caselaw_marklogic_api_client-39.2.0/src/caselawclient/models/documents/comparison.py +42 -0
  8. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/identifiers/__init__.py +4 -2
  9. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/judgments.py +1 -0
  10. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/parser_logs.py +1 -0
  11. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/press_summaries.py +1 -0
  12. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/utilities/aws.py +2 -0
  13. ds_caselaw_marklogic_api_client-39.0.0/src/caselawclient/__init__.py +0 -40
  14. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/LICENSE.md +0 -0
  15. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/client_helpers/__init__.py +0 -0
  16. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/client_helpers/search_helpers.py +0 -0
  17. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/content_hash.py +0 -0
  18. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/errors.py +0 -0
  19. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/factories.py +0 -0
  20. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/identifier_resolution.py +0 -0
  21. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/__init__.py +0 -0
  22. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/documents/body.py +0 -0
  23. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/documents/exceptions.py +0 -0
  24. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/documents/statuses.py +0 -0
  25. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/documents/transforms/html.xsl +0 -0
  26. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/documents/xml.py +0 -0
  27. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/identifiers/collection.py +0 -0
  28. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/identifiers/exceptions.py +0 -0
  29. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/identifiers/fclid.py +0 -0
  30. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/identifiers/neutral_citation.py +0 -0
  31. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/identifiers/press_summary_ncn.py +0 -0
  32. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/identifiers/unpacker.py +0 -0
  33. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/neutral_citation_mixin.py +0 -0
  34. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/utilities/__init__.py +0 -0
  35. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/utilities/dates.py +0 -0
  36. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/models/utilities/move.py +0 -0
  37. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/py.typed +0 -0
  38. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/responses/__init__.py +0 -0
  39. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/responses/search_response.py +0 -0
  40. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/responses/search_result.py +0 -0
  41. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/responses/xsl/search_match.xsl +0 -0
  42. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/search_parameters.py +0 -0
  43. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/types.py +0 -0
  44. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xml_helpers.py +0 -0
  45. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/break_judgment_checkout.xqy +0 -0
  46. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/checkin_judgment.xqy +0 -0
  47. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/checkout_judgment.xqy +0 -0
  48. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/copy_document.xqy +0 -0
  49. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/delete_judgment.xqy +0 -0
  50. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/document_collections.xqy +0 -0
  51. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/document_exists.xqy +0 -0
  52. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_combined_stats_table.xqy +0 -0
  53. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_components_for_document.xqy +0 -0
  54. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_highest_enrichment_version.xqy +0 -0
  55. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_highest_parser_version.xqy +0 -0
  56. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_judgment.xqy +0 -0
  57. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_judgment_checkout_status.xqy +0 -0
  58. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_judgment_version.xqy +0 -0
  59. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_last_modified.xqy +0 -0
  60. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_missing_fclid.xqy +0 -0
  61. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_next_document_sequence_number.xqy +0 -0
  62. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_pending_enrichment_for_version.xqy +0 -0
  63. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_pending_parse_for_version.xqy +0 -0
  64. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_properties_for_search_results.xqy +0 -0
  65. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_property.xqy +0 -0
  66. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_property_as_node.xqy +0 -0
  67. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_recently_enriched.xqy +0 -0
  68. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_recently_parsed.xqy +0 -0
  69. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_version_annotation.xqy +0 -0
  70. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/get_version_created.xqy +0 -0
  71. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/insert_document.xqy +0 -0
  72. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/list_judgment_versions.xqy +0 -0
  73. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/resolve_from_identifier_slug.xqy +0 -0
  74. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/resolve_from_identifier_value.xqy +0 -0
  75. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_boolean_property.xqy +0 -0
  76. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_metadata_citation.xqy +0 -0
  77. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_metadata_court.xqy +0 -0
  78. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_metadata_jurisdiction.xqy +0 -0
  79. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_metadata_name.xqy +0 -0
  80. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_metadata_this_uri.xqy +0 -0
  81. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_metadata_work_expression_date.xqy +0 -0
  82. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_property.xqy +0 -0
  83. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/set_property_as_node.xqy +0 -0
  84. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/update_document.xqy +0 -0
  85. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/update_locked_judgment.xqy +0 -0
  86. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/user_has_privilege.xqy +0 -0
  87. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/user_has_role.xqy +0 -0
  88. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/validate_all_documents.xqy +0 -0
  89. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/validate_document.xqy +0 -0
  90. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/xslt.xqy +0 -0
  91. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery/xslt_transform.xqy +0 -0
  92. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xquery_type_dicts.py +0 -0
  93. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xslt/modify_xml_live.xsl +0 -0
  94. {ds_caselaw_marklogic_api_client-39.0.0 → ds_caselaw_marklogic_api_client-39.2.0}/src/caselawclient/xslt/sample.xsl +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ds-caselaw-marklogic-api-client
3
- Version: 39.0.0
3
+ Version: 39.2.0
4
4
  Summary: An API client for interacting with the underlying data in Find Caselaw.
5
5
  Keywords: national archives,caselaw
6
6
  Author: The National Archives
@@ -11,12 +11,13 @@ Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3.13
13
13
  Requires-Dist: boto3 (>=1.26.112,<2.0.0)
14
- Requires-Dist: certifi (>=2025.7.9,<2025.8.0)
14
+ Requires-Dist: certifi (>=2025.8.3,<2025.9.0)
15
15
  Requires-Dist: charset-normalizer (>=3.0.0,<4.0.0)
16
+ Requires-Dist: defusedxml (>=0.7.1,<0.8.0)
16
17
  Requires-Dist: django-environ (>=0.12.0)
17
18
  Requires-Dist: ds-caselaw-utils (>=2.0.0,<3.0.0)
18
19
  Requires-Dist: idna (>=3.4,<4.0)
19
- Requires-Dist: lxml (>=5.0.0,<6.0.0)
20
+ Requires-Dist: lxml (>=6.0.0,<7.0.0)
20
21
  Requires-Dist: memoization (>=0.4.0,<0.5.0)
21
22
  Requires-Dist: mypy-boto3-s3 (>=1.26.104,<2.0.0)
22
23
  Requires-Dist: mypy-boto3-sns (>=1.26.69,<2.0.0)
@@ -36,7 +37,9 @@ This repository is part of the [Find Case Law](https://caselaw.nationalarchives.
36
37
 
37
38
  # MarkLogic API Client
38
39
 
39
- [![PyPI](https://img.shields.io/pypi/v/ds-caselaw-marklogic-api-client)](https://pypi.org/project/ds-caselaw-marklogic-api-client/) ![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/pypi/ds-caselaw-marklogic-api-client)
40
+ [![PyPI](https://img.shields.io/pypi/v/ds-caselaw-marklogic-api-client)](https://pypi.org/project/ds-caselaw-marklogic-api-client/)
41
+ ![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/pypi/ds-caselaw-marklogic-api-client)
42
+ ![Code Coverage](https://img.shields.io/codecov/c/github/nationalarchives/ds-caselaw-custom-api-client)
40
43
 
41
44
  This is an API Client for connecting to Marklogic for The National Archive's Caselaw site.
42
45
 
@@ -4,7 +4,9 @@ This repository is part of the [Find Case Law](https://caselaw.nationalarchives.
4
4
 
5
5
  # MarkLogic API Client
6
6
 
7
- [![PyPI](https://img.shields.io/pypi/v/ds-caselaw-marklogic-api-client)](https://pypi.org/project/ds-caselaw-marklogic-api-client/) ![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/pypi/ds-caselaw-marklogic-api-client)
7
+ [![PyPI](https://img.shields.io/pypi/v/ds-caselaw-marklogic-api-client)](https://pypi.org/project/ds-caselaw-marklogic-api-client/)
8
+ ![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/pypi/ds-caselaw-marklogic-api-client)
9
+ ![Code Coverage](https://img.shields.io/codecov/c/github/nationalarchives/ds-caselaw-custom-api-client)
8
10
 
9
11
  This is an API Client for connecting to Marklogic for The National Archive's Caselaw site.
10
12
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ds-caselaw-marklogic-api-client"
3
- version = "39.0.0"
3
+ version = "39.2.0"
4
4
  description = "An API client for interacting with the underlying data in Find Caselaw."
5
5
  authors = ["The National Archives"]
6
6
  homepage = "https://github.com/nationalarchives/ds-caselaw-custom-api-client"
@@ -12,14 +12,14 @@ packages = [
12
12
 
13
13
  [tool.poetry.dependencies]
14
14
  python = "^3.10.0"
15
- certifi = ">=2025.7.9,<2025.8.0"
15
+ certifi = ">=2025.8.3,<2025.9.0"
16
16
  charset-normalizer = "^3.0.0"
17
17
  django-environ = ">=0.12.0"
18
18
  idna = "^3.4"
19
19
  requests = "^2.28.2"
20
20
  requests-toolbelt = ">=0.10.1,<1.1.0"
21
21
  memoization = "^0.4.0"
22
- lxml = "^5.0.0"
22
+ lxml = "^6.0.0"
23
23
  ds-caselaw-utils = "^2.0.0"
24
24
  boto3 = "^1.26.112"
25
25
  typing-extensions = "^4.7.1"
@@ -29,15 +29,17 @@ pytz = ">2024"
29
29
  python-dateutil = "^2.9.0-post.0"
30
30
  saxonche = "^12.5.0"
31
31
  sqids = "^0.5.0"
32
+ defusedxml = "^0.7.1"
32
33
 
33
34
  [tool.poetry.group.dev.dependencies]
34
- coverage = "7.9.2"
35
+ coverage = "7.10.3"
35
36
  pytest = "8.4.1"
37
+ pytest-cov = "6.2.1"
36
38
  beautifulsoup4 = "4.13.4"
37
- responses = "0.25.7"
39
+ responses = "0.25.8"
38
40
  python-dotenv = "1.1.1"
39
- time-machine = "2.16.0"
40
- moto = {version = "5.1.8", extras = ["all"]}
41
+ time-machine = "2.17.0"
42
+ moto = {version = "5.1.9", extras = ["all"]}
41
43
 
42
44
  [tool.poetry.group.docs]
43
45
  optional = true
@@ -69,14 +71,15 @@ line-length = 120
69
71
 
70
72
  [tool.ruff.lint]
71
73
  ignore = ["E501", "G004", "PLR2004", "RUF005", "RUF012", "UP040"] # longlines, fstrings in logs, magic values, consider not concat, mutable classbits, type instead of TypeAlias
72
- extend-select = ["W", "I", "SLF", "SIM"]
73
- # extend-select = [ "B", "Q", "C90", "I", "UP", "YTT", "ASYNC", "S", "BLE", "A", "COM", "C4", "DTZ", "T10", "DJ", "EM", "EXE", "FA",
74
+ extend-select = ["W", "I", "SLF", "SIM", "C90", "S"]
75
+ # extend-select = [ "B", "Q", "I", "UP", "YTT", "ASYNC", "BLE", "A", "COM", "C4", "DTZ", "T10", "DJ", "EM", "EXE", "FA",
74
76
  # "ISC", "ICN", "G", "INP", "PIE", "T20", "PYI", "PT", "Q", "RSE", "RET", "SLOT", "TID", "TCH", "INT", "PTH",
75
77
  # "FIX", "PGH", "PL", "TRY", "FLY", "PERF", "RUF"]
76
78
  unfixable = ["ERA"]
77
79
 
78
80
  [tool.ruff.lint.extend-per-file-ignores]
79
- "tests/*" = ["S101"] # `assert` is fine in tests
81
+ "tests/*" = ["S101"] # `assert` is fine in tests
82
+ "smoketest/*" = ["S101"] # `assert` is fine in tests
80
83
  "tests/client/test_client.py" = ["SLF001"] # TODO: This really shouldn't be the case, but it's not important to fix right now.
81
84
 
82
85
  # things skipped:
@@ -7,11 +7,12 @@ import warnings
7
7
  from datetime import datetime, time, timedelta
8
8
  from pathlib import Path
9
9
  from typing import Any, Optional, Type, Union
10
- from xml.etree import ElementTree
11
- from xml.etree.ElementTree import Element, ParseError, fromstring
10
+ from xml.etree.ElementTree import Element
12
11
 
13
12
  import environ
14
13
  import requests
14
+ from defusedxml import ElementTree
15
+ from defusedxml.ElementTree import ParseError, fromstring
15
16
  from ds_caselaw_utils.types import NeutralCitationString
16
17
  from lxml import etree
17
18
  from requests.auth import HTTPBasicAuth
@@ -55,6 +56,11 @@ from .errors import (
55
56
  )
56
57
 
57
58
  env = environ.Env()
59
+
60
+ # Requests timeouts: https://requests.readthedocs.io/en/latest/user/advanced/
61
+ CONNECT_TIMEOUT = float(os.environ.get("CONNECT_TIMEOUT", "3.05"))
62
+ READ_TIMEOUT = float(os.environ.get("READ_TIMEOUT", "10.0"))
63
+
58
64
  ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
59
65
  DEFAULT_XSL_TRANSFORM = "accessible-html.xsl"
60
66
 
@@ -169,6 +175,7 @@ class MarklogicApiClient:
169
175
  error_code_classes: dict[str, Type[MarklogicAPIError]] = {
170
176
  "XDMP-DOCNOTFOUND": MarklogicResourceNotFoundError,
171
177
  "XDMP-LOCKCONFLICT": MarklogicResourceLockedError,
178
+ "XDMP-LOCKED": MarklogicResourceLockedError,
172
179
  "DLS-UNMANAGED": MarklogicResourceUnmanagedError,
173
180
  "DLS-NOTCHECKEDOUT": MarklogicResourceNotCheckedOutError,
174
181
  "DLS-CHECKOUTCONFLICT": MarklogicCheckoutConflictError,
@@ -258,10 +265,12 @@ class MarklogicApiClient:
258
265
  return "Unknown error, Marklogic returned a null or empty response"
259
266
  try:
260
267
  xml = fromstring(content_as_xml)
261
- return xml.find(
262
- "message-code",
263
- namespaces={"": "http://marklogic.com/xdmp/error"},
264
- ).text # type: ignore
268
+ return str(
269
+ xml.find(
270
+ "message-code",
271
+ namespaces={"": "http://marklogic.com/xdmp/error"},
272
+ ).text
273
+ )
265
274
  except (ParseError, TypeError, AttributeError):
266
275
  return "Unknown error, Marklogic returned a null or empty response"
267
276
 
@@ -314,11 +323,13 @@ class MarklogicApiClient:
314
323
  self,
315
324
  vars: query_dicts.MarkLogicAPIDict,
316
325
  xquery_file_name: str,
326
+ timeout: tuple[float, float] = (CONNECT_TIMEOUT, READ_TIMEOUT),
317
327
  ) -> requests.Response:
318
328
  return self.eval(
319
329
  self._xquery_path(xquery_file_name),
320
330
  vars=json.dumps(vars),
321
331
  accept_header="application/xml",
332
+ timeout=timeout,
322
333
  )
323
334
 
324
335
  def _eval_and_decode(
@@ -682,10 +693,12 @@ class MarklogicApiClient:
682
693
  if content == "":
683
694
  return None
684
695
  response_xml = ElementTree.fromstring(content)
685
- return response_xml.find(
686
- "dls:annotation",
687
- namespaces={"dls": "http://marklogic.com/xdmp/dls"},
688
- ).text # type: ignore
696
+ return str(
697
+ response_xml.find(
698
+ "dls:annotation",
699
+ namespaces={"dls": "http://marklogic.com/xdmp/dls"},
700
+ ).text
701
+ )
689
702
 
690
703
  def get_judgment_version(
691
704
  self,
@@ -719,6 +732,7 @@ class MarklogicApiClient:
719
732
  xquery_path: str,
720
733
  vars: str,
721
734
  accept_header: str = "multipart/mixed",
735
+ timeout: tuple[float, float] = (CONNECT_TIMEOUT, READ_TIMEOUT),
722
736
  ) -> requests.Response:
723
737
  headers = {
724
738
  "Content-type": "application/x-www-form-urlencoded",
@@ -738,6 +752,7 @@ class MarklogicApiClient:
738
752
  url=self._path_to_request_url(path),
739
753
  headers=headers,
740
754
  data=data,
755
+ timeout=timeout,
741
756
  )
742
757
  # Raise relevant exception for an erroneous response
743
758
  self._raise_for_status(response)
@@ -1047,10 +1062,6 @@ class MarklogicApiClient:
1047
1062
  if show_unpublished and not self.user_can_view_unpublished_judgments(
1048
1063
  self.username,
1049
1064
  ):
1050
- # The user cannot view unpublished judgments but is requesting to see them
1051
- logging.warning(
1052
- f"User {self.username} is attempting to view unpublished judgments but does not have that privilege.",
1053
- )
1054
1065
  return False
1055
1066
  return show_unpublished
1056
1067
 
@@ -0,0 +1,63 @@
1
+ import os
2
+
3
+ if os.getenv("PDOC_DYNAMIC_VERSION") == "1":
4
+ from pathlib import Path
5
+
6
+ import tomllib
7
+
8
+ pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
9
+ with pyproject_path.open("rb") as f:
10
+ __version__ = tomllib.load(f)["tool"]["poetry"]["version"]
11
+ __pip_version_string__ = f"~={__version__}"
12
+ __poetry_version_string__ = f' = "^{__version__}"'
13
+
14
+ else:
15
+ __pip_version_string__ = ""
16
+ __poetry_version_string__ = ""
17
+
18
+ __doc__ = f"""
19
+
20
+ # Installation
21
+
22
+ Include the API client in your project using Pip or Poetry:
23
+
24
+ ```bash
25
+ pip install ds-caselaw-marklogic-api-client
26
+ ```
27
+
28
+ ```bash
29
+ poetry add ds-caselaw-marklogic-api-client
30
+ ```
31
+
32
+ or in your projects `requirements.txt` with:
33
+
34
+ ```text
35
+ ds-caselaw-marklogic-api-client{__pip_version_string__}
36
+ ```
37
+
38
+ or `pyproject.toml` for Poetry with:
39
+
40
+ ```text
41
+ ds-caselaw-marklogic-api-client{__poetry_version_string__}
42
+ ```
43
+
44
+ # Usage
45
+
46
+ ## Initialising the client
47
+
48
+ Import the `MarklogicApiClient` class and instantiate with appropriate credentials:
49
+
50
+ ```python
51
+
52
+ from caselawclient.Client import MarklogicApiClient
53
+
54
+ client = MarklogicApiClient(
55
+ host="hostname",
56
+ username="username",
57
+ password="password",
58
+ use_https=True,
59
+ )
60
+
61
+ ```
62
+
63
+ """
@@ -9,6 +9,7 @@ from ds_caselaw_utils.courts import CourtNotFoundException
9
9
  from ds_caselaw_utils.types import NeutralCitationString
10
10
  from requests_toolbelt.multipart import decoder
11
11
 
12
+ import caselawclient.models.documents.comparison as comparison
12
13
  from caselawclient.errors import (
13
14
  DocumentNotFoundError,
14
15
  NotSupportedOnVersion,
@@ -63,6 +64,9 @@ class Document:
63
64
  document_noun_plural = "documents"
64
65
  """ The noun for a plural of this document type. """
65
66
 
67
+ _default_reparse_document_type: Optional[str] = None
68
+ """ The default noun to pass to the parser when reparsing given the document type if known. This is used to determine how the document should be parsed and processed."""
69
+
66
70
  type_collection_name: str
67
71
 
68
72
  attributes_to_validate: list[tuple[str, bool, str]] = [
@@ -465,7 +469,6 @@ class Document:
465
469
  now = datetime.datetime.now(datetime.timezone.utc)
466
470
  self.api_client.set_property(self.uri, "last_sent_to_parser", now.isoformat())
467
471
 
468
- parser_type_noun = {"judgment": "judgment", "press summary": "pressSummary"}[self.document_noun]
469
472
  checked_date: Optional[str] = (
470
473
  self.body.document_date_as_date.isoformat()
471
474
  if self.body.document_date_as_date and self.body.document_date_as_date > datetime.date(1001, 1, 1)
@@ -477,16 +480,18 @@ class Document:
477
480
  # values are "" from the API, we should pass None instead in this case.
478
481
 
479
482
  parser_instructions: ParserInstructionsDict = {
480
- "documentType": parser_type_noun,
481
483
  "metadata": {
482
484
  "name": self.body.name or None,
483
485
  "cite": None,
484
486
  "court": self.body.court or None,
485
487
  "date": checked_date,
486
488
  "uri": self.uri,
487
- },
489
+ }
488
490
  }
489
491
 
492
+ if self._default_reparse_document_type:
493
+ parser_instructions["documentType"] = self._default_reparse_document_type
494
+
490
495
  ## TODO: Remove this hack around the fact that NCNs are assumed to be present for all documents' metadata, but actually different document classes may have different metadata
491
496
  if hasattr(self, "neutral_citation"):
492
497
  parser_instructions["metadata"]["cite"] = self.neutral_citation
@@ -579,3 +584,6 @@ class Document:
579
584
  return self.body.apply_xslt(
580
585
  "modify_xml_live.xsl", work_uri=work_uri, expression_uri=expression_uri, manifestation_uri=manifestation_uri
581
586
  )
587
+
588
+ def compare_to(self, that_doc: "Document") -> comparison.Comparison:
589
+ return comparison.Comparison(self, that_doc)
@@ -0,0 +1,42 @@
1
+ from typing import TypedDict
2
+
3
+ import caselawclient.models.documents
4
+
5
+
6
+ class AttributeComparison(TypedDict):
7
+ """Results from a comparison of one attribute across two documents"""
8
+
9
+ label: str
10
+ this_value: str
11
+ that_value: str
12
+ match: bool
13
+
14
+
15
+ class Comparison(dict[str, AttributeComparison]):
16
+ def __init__(
17
+ self, this_doc: "caselawclient.models.documents.Document", that_doc: "caselawclient.models.documents.Document"
18
+ ):
19
+ # court, date, title
20
+ self["court"] = AttributeComparison(
21
+ label="court",
22
+ this_value=this_doc.court,
23
+ that_value=that_doc.court,
24
+ match=this_doc.court == that_doc.court,
25
+ )
26
+
27
+ self["date"] = AttributeComparison(
28
+ label="date",
29
+ this_value=this_doc.body.document_date_as_string,
30
+ that_value=that_doc.body.document_date_as_string,
31
+ match=this_doc.body.document_date_as_string == that_doc.body.document_date_as_string,
32
+ )
33
+ self["name"] = AttributeComparison(
34
+ label="name",
35
+ this_value=this_doc.name,
36
+ that_value=that_doc.name,
37
+ match=this_doc.name == that_doc.name,
38
+ )
39
+
40
+ def match(self) -> bool:
41
+ """Is this comparison an exact match across all attributes?"""
42
+ return all(x["match"] for x in self.values())
@@ -166,8 +166,10 @@ class Identifier(ABC):
166
166
  """
167
167
  resolutions = [
168
168
  resolution
169
- for resolution in api_client.resolve_from_identifier_value(identifier_value=self.value)
170
- if resolution.identifier_namespace == self.schema.namespace
169
+ for resolution in api_client.resolve_from_identifier_value(
170
+ identifier_value=self.value, published_only=False
171
+ )
172
+ if resolution.identifier_namespace == self.schema.namespace and resolution.identifier_uuid != self.uuid
171
173
  ]
172
174
  if len(resolutions) > 0:
173
175
  return SuccessFailureMessageTuple(
@@ -24,6 +24,7 @@ class Judgment(NeutralCitationMixin, Document):
24
24
  document_noun = "judgment"
25
25
  document_noun_plural = "judgments"
26
26
  type_collection_name = "judgment"
27
+ _default_reparse_document_type = "judgment"
27
28
 
28
29
  def __init__(self, uri: DocumentURIString, *args: Any, **kwargs: Any) -> None:
29
30
  super().__init__(self.document_noun, uri, *args, **kwargs)
@@ -11,3 +11,4 @@ class ParserLog(Document):
11
11
  document_noun = "parser log"
12
12
  document_noun_plural = "parser logs"
13
13
  type_collection_name = "parser-log"
14
+ _default_reparse_document_type = "parserLog"
@@ -25,6 +25,7 @@ class PressSummary(NeutralCitationMixin, Document):
25
25
  document_noun = "press summary"
26
26
  document_noun_plural = "press summaries"
27
27
  type_collection_name = "press-summary"
28
+ _default_reparse_document_type = "pressSummary"
28
29
 
29
30
  def __init__(self, uri: DocumentURIString, *args: Any, **kwargs: Any) -> None:
30
31
  super().__init__(self.document_noun, uri, *args, **kwargs)
@@ -96,6 +96,8 @@ def check_docx_exists(uri: DocumentURIString) -> bool:
96
96
  except botocore.exceptions.ClientError as e:
97
97
  if e.response["Error"]["Code"] == "404":
98
98
  return False
99
+ if e.response["Error"]["Code"] == "403":
100
+ e.add_note("403 on reading {s3_key}")
99
101
  raise
100
102
 
101
103
 
@@ -1,40 +0,0 @@
1
- """
2
-
3
- # Installation
4
-
5
- Include the API client in your project using Pip or Poetry:
6
-
7
- ```bash
8
- pip install ds-caselaw-marklogic-api-client
9
- ```
10
-
11
- ```bash
12
- poetry add ds-caselaw-marklogic-api-client
13
- ```
14
-
15
- or in your projects `requirements.txt` with:
16
-
17
- ```text
18
- ds-caselaw-marklogic-api-client~=12.0.0
19
- ```
20
-
21
- # Usage
22
-
23
- ## Initialising the client
24
-
25
- Import the `MarklogicApiClient` class and instantiate with appropriate credentials:
26
-
27
- ```python
28
-
29
- from caselawclient.Client import MarklogicApiClient
30
-
31
- client = MarklogicApiClient(
32
- host="hostname",
33
- username="username",
34
- password="password",
35
- use_https=True,
36
- )
37
-
38
- ```
39
-
40
- """