pyUSPTO 0.5.3__tar.gz → 0.5.4__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.
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.devcontainer/devcontainer.json +4 -1
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.gitignore +1 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/CHANGELOG.md +10 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/PKG-INFO +2 -2
- {pyuspto-0.5.3 → pyuspto-0.5.4}/README.md +1 -1
- {pyuspto-0.5.3 → pyuspto-0.5.4}/requirements-dev.txt +7 -7
- {pyuspto-0.5.3 → pyuspto-0.5.4}/requirements.txt +3 -3
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/patent_data.py +32 -13
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/config.py +79 -50
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/patent_data.py +5 -1
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO.egg-info/PKG-INFO +2 -2
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_base.py +9 -27
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_oa_citations_clients.py +5 -14
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_oa_rejections_clients.py +4 -4
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_patent_data_clients.py +69 -8
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_petition_decision_clients.py +1 -3
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_oa_actions_integration.py +4 -12
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_oa_citations_integration.py +4 -12
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_oa_rejections_integration.py +3 -9
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_patent_data_integration.py +6 -6
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_petition_decisions_integration.py +9 -9
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_ptab_appeals_integration.py +6 -6
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_ptab_interferences_integration.py +13 -13
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_ptab_trials_integration.py +12 -12
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_bulk_data_models.py +12 -4
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_enriched_citation_models.py +3 -9
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_oa_actions_models.py +15 -3
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_oa_citations_models.py +8 -20
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_oa_rejections_models.py +2 -6
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/test_edge_cases.py +1 -1
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/test_init.py +3 -3
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.devcontainer/devcontainer-lock.json +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/ISSUE_TEMPLATE/documentation-updates.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/dependabot.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/workflows/codeql.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/workflows/publish-docs.yaml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/workflows/publish-to-test-pypi.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.github/workflows/python-tests.yml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/.readthedocs.yaml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/ADVANCED.md +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/CODE_OF_CONDUCT.md +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/CONTRIBUTING.md +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/LICENSE +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/_version.pyi +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/Makefile +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/_static/.gitkeep +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/about.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/advanced.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/bulk_data.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/enriched_citations.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/index.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/oa_actions.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/oa_citations.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/oa_rejections.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/patent_data.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/petition_decisions.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/ptab_appeals.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/ptab_interferences.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/clients/ptab_trials.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/config/config.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/config/http_config.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/config/index.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/exceptions.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/index.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/base.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/bulk_data.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/enriched_citations.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/index.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/oa_actions.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/oa_citations.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/oa_rejections.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/patent_data.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/petition_decisions.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/ptab.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/models/utils.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/api/warnings.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/conf.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/configuration.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/development.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/bulk_data.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/enriched_citations.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/ifw_example.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/index.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/oa_actions.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/oa_citations.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/oa_rejections.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/patent_data.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/petition_decisions.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/ptab_appeals.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/ptab_interferences.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/examples/ptab_trials.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/index.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/installation.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/docs/source/quickstart.rst +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/bulk_data_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/enriched_citations_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/error_handling_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/ifw_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/oa_actions_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/oa_citations_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/oa_rejections_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/patent_data_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/petition_decisions_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/ptab_appeals_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/ptab_interferences_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/examples/ptab_trials_example.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/pyUSPTO.code-workspace +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/pyproject.toml +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/setup.cfg +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/base.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/bulk_data.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/enriched_citations.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/oa_actions.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/oa_citations.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/oa_rejections.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/petition_decisions.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/ptab_appeals.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/ptab_interferences.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/clients/ptab_trials.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/exceptions.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/http_config.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/base.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/bulk_data.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/enriched_citations.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/oa_actions.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/oa_citations.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/oa_rejections.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/petition_decisions.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/ptab.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/models/utils.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/py.typed +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/utils/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO/warnings.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO.egg-info/SOURCES.txt +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO.egg-info/dependency_links.txt +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO.egg-info/requires.txt +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO.egg-info/top_level.txt +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/src/pyUSPTO.egg-info/zip-safe +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_bulk_data_clients.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_enriched_citation_clients.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_oa_actions_clients.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_ptab_appeals_client.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_ptab_interferences_client.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/clients/test_ptab_trials_client.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/conftest.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/conftest.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_bulk_data_integration.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/integration/test_enriched_citations_integration.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_patent_data_models.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_petition_decision_models.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_ptab_models.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/models/test_utils.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/test_config.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/test_exceptions.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/test_http_config.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/test_version.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tests/utils/__init__.py +0 -0
- {pyuspto-0.5.3 → pyuspto-0.5.4}/tox.ini +0 -0
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
"build": { "dockerfile": "Dockerfile" },
|
|
4
4
|
"features": {
|
|
5
5
|
"ghcr.io/devcontainers/features/git:1": {},
|
|
6
|
-
"ghcr.io/devcontainers/features/node:2": {}
|
|
6
|
+
"ghcr.io/devcontainers/features/node:2": {},
|
|
7
|
+
"ghcr.io/devcontainers/features/powershell:2.0.2": {
|
|
8
|
+
"version": "latest"
|
|
9
|
+
}
|
|
7
10
|
},
|
|
8
11
|
"mounts": [
|
|
9
12
|
"source=pyuspto-claude-home,target=/home/vscode/.claude,type=volume"
|
|
@@ -5,6 +5,16 @@ All notable changes to the pyUSPTO package will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Breaking**: `sanitize_application_number` now emits the standardized 15-character PCT format (`PCT` + 2-char country + 4-digit year + 6-digit zero-padded serial, e.g. `PCTUS2024012345`) per USPTO ODP Release 3.6 (2026-04-10). Previously emitted a non-standard 12-character form (e.g. `PCTUS2412345`). Affects every endpoint that takes a PCT application number, including `get_pct`, `get_application_by_number`, and `get_IFW_metadata(PCT_app_number=...)`. 2-digit year inputs are expanded via a sliding window (YY≥78 → 19YY, else 20YY). Legacy 12-character PCT strings are no longer accepted as input.
|
|
13
|
+
|
|
14
|
+
### Deprecated
|
|
15
|
+
|
|
16
|
+
- `Address.country_or_state_code` — USPTO ODP Release 3.6 removed `countryOrStateCode` from the Patent Assignment API response; the location data now lives in `geographicRegionCode` (already exposed as `Address.geographic_region_code`). The attribute remains for backward compatibility and will be `None` for responses from updated endpoints.
|
|
17
|
+
|
|
8
18
|
## [0.4.5] - 2026-03-11
|
|
9
19
|
|
|
10
20
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyUSPTO
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: A Modern Python client for accessing the United States Patent and Trademark Office (USPTO) Open Data Portal (ODP) APIs.
|
|
5
5
|
Author-email: Andrew Piechocki <apiechocki@dunlapcodding.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -201,7 +201,7 @@ if app.application_meta_data:
|
|
|
201
201
|
wrapper = client.get_IFW_metadata(application_number="18/045,436")
|
|
202
202
|
wrapper = client.get_IFW_metadata(patent_number="11,234,567")
|
|
203
203
|
wrapper = client.get_IFW_metadata(publication_number="2023/0012345")
|
|
204
|
-
wrapper = client.get_IFW_metadata(PCT_app_number="PCT/
|
|
204
|
+
wrapper = client.get_IFW_metadata(PCT_app_number="PCT/US2024/012345")
|
|
205
205
|
|
|
206
206
|
# Look up USPTO status codes
|
|
207
207
|
status_codes = client.get_status_codes()
|
|
@@ -134,7 +134,7 @@ if app.application_meta_data:
|
|
|
134
134
|
wrapper = client.get_IFW_metadata(application_number="18/045,436")
|
|
135
135
|
wrapper = client.get_IFW_metadata(patent_number="11,234,567")
|
|
136
136
|
wrapper = client.get_IFW_metadata(publication_number="2023/0012345")
|
|
137
|
-
wrapper = client.get_IFW_metadata(PCT_app_number="PCT/
|
|
137
|
+
wrapper = client.get_IFW_metadata(PCT_app_number="PCT/US2024/012345")
|
|
138
138
|
|
|
139
139
|
# Look up USPTO status codes
|
|
140
140
|
status_codes = client.get_status_codes()
|
|
@@ -8,7 +8,7 @@ alabaster==1.0.0
|
|
|
8
8
|
# via sphinx
|
|
9
9
|
babel==2.18.0
|
|
10
10
|
# via sphinx
|
|
11
|
-
certifi==2026.
|
|
11
|
+
certifi==2026.5.20
|
|
12
12
|
# via requests
|
|
13
13
|
charset-normalizer==3.4.7
|
|
14
14
|
# via requests
|
|
@@ -16,14 +16,14 @@ colorama==0.4.6
|
|
|
16
16
|
# via
|
|
17
17
|
# pytest
|
|
18
18
|
# sphinx
|
|
19
|
-
coverage==7.14.
|
|
19
|
+
coverage==7.14.1
|
|
20
20
|
# via pytest-cov
|
|
21
21
|
docutils==0.22.4
|
|
22
22
|
# via
|
|
23
23
|
# myst-parser
|
|
24
24
|
# sphinx
|
|
25
25
|
# sphinx-rtd-theme
|
|
26
|
-
idna==3.
|
|
26
|
+
idna==3.16
|
|
27
27
|
# via requests
|
|
28
28
|
imagesize==2.0.0
|
|
29
29
|
# via sphinx
|
|
@@ -76,16 +76,16 @@ pytest-mock==3.15.1
|
|
|
76
76
|
# via pyuspto
|
|
77
77
|
pyyaml==6.0.3
|
|
78
78
|
# via myst-parser
|
|
79
|
-
requests==2.34.
|
|
79
|
+
requests==2.34.2
|
|
80
80
|
# via
|
|
81
81
|
# pyUSPTO (pyproject.toml)
|
|
82
82
|
# pyuspto
|
|
83
83
|
# sphinx
|
|
84
84
|
roman-numerals==4.1.0
|
|
85
85
|
# via sphinx
|
|
86
|
-
ruff==0.15.
|
|
86
|
+
ruff==0.15.14
|
|
87
87
|
# via pyuspto
|
|
88
|
-
snowballstemmer==3.0
|
|
88
|
+
snowballstemmer==3.1.0
|
|
89
89
|
# via sphinx
|
|
90
90
|
sphinx==9.1.0
|
|
91
91
|
# via
|
|
@@ -115,7 +115,7 @@ sphinxcontrib-qthelp==2.0.0
|
|
|
115
115
|
# via sphinx
|
|
116
116
|
sphinxcontrib-serializinghtml==2.0.0
|
|
117
117
|
# via sphinx
|
|
118
|
-
types-requests==2.33.0.
|
|
118
|
+
types-requests==2.33.0.20260518
|
|
119
119
|
# via pyuspto
|
|
120
120
|
typing-extensions==4.15.0
|
|
121
121
|
# via
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
#
|
|
5
5
|
# pip-compile --output-file=requirements.txt --strip-extras pyproject.toml
|
|
6
6
|
#
|
|
7
|
-
certifi==2026.
|
|
7
|
+
certifi==2026.5.20
|
|
8
8
|
# via requests
|
|
9
9
|
charset-normalizer==3.4.7
|
|
10
10
|
# via requests
|
|
11
|
-
idna==3.
|
|
11
|
+
idna==3.16
|
|
12
12
|
# via requests
|
|
13
|
-
requests==2.34.
|
|
13
|
+
requests==2.34.2
|
|
14
14
|
# via pyUSPTO (pyproject.toml)
|
|
15
15
|
tzdata==2026.2
|
|
16
16
|
# via pyUSPTO (pyproject.toml)
|
|
@@ -93,7 +93,8 @@ class PatentDataClient(BaseUSPTOClient[PatentDataResponse]):
|
|
|
93
93
|
Application numbers are either:
|
|
94
94
|
- 8 digits (e.g., "16123456")
|
|
95
95
|
- Series code format: 2 digits + "/" + 6 digits (e.g., "08/123456")
|
|
96
|
-
- PCT format: "PCT/US2024/012345" → "
|
|
96
|
+
- PCT format: "PCT/US2024/012345" → "PCTUS2024012345"
|
|
97
|
+
(standardized 15-character form per USPTO ODP Release 3.6, 2026-04-10)
|
|
97
98
|
|
|
98
99
|
This method removes common separators (commas, spaces) while preserving
|
|
99
100
|
the "/" in series code format.
|
|
@@ -103,7 +104,8 @@ class PatentDataClient(BaseUSPTOClient[PatentDataResponse]):
|
|
|
103
104
|
spaces, or other formatting.
|
|
104
105
|
|
|
105
106
|
Returns:
|
|
106
|
-
str: Sanitized application number (
|
|
107
|
+
str: Sanitized application number ("NNNNNNNN", "NN/NNNNNN", or
|
|
108
|
+
"PCT" + 2-char country + 4-digit year + 6-digit serial).
|
|
107
109
|
|
|
108
110
|
Raises:
|
|
109
111
|
ValueError: If the format is invalid.
|
|
@@ -117,19 +119,28 @@ class PatentDataClient(BaseUSPTOClient[PatentDataResponse]):
|
|
|
117
119
|
"08/123456"
|
|
118
120
|
>>> client.sanitize_application_number("08/123,456")
|
|
119
121
|
"08/123456"
|
|
122
|
+
>>> client.sanitize_application_number("PCT/US2024/012345")
|
|
123
|
+
"PCTUS2024012345"
|
|
120
124
|
"""
|
|
121
125
|
if not input_number or not input_number.strip():
|
|
122
126
|
raise ValueError("Application number cannot be empty")
|
|
123
127
|
|
|
124
128
|
raw = input_number.strip()
|
|
125
129
|
|
|
126
|
-
#
|
|
127
|
-
#
|
|
130
|
+
# Handle PCT formats. Output is the standardized 15-char form:
|
|
131
|
+
# "PCT" + 2-char country + 4-digit year + 6-digit zero-padded serial.
|
|
132
|
+
# Example: "PCT/US2024/012345" -> "PCTUS2024012345"
|
|
128
133
|
if raw.startswith("PCT"):
|
|
129
134
|
parts = raw.split("/")
|
|
130
135
|
if len(parts) == 1:
|
|
131
|
-
#
|
|
132
|
-
|
|
136
|
+
# No slashes — only accept input that is already in the 15-char form.
|
|
137
|
+
body = raw[3:]
|
|
138
|
+
if len(body) == 12 and body[:2].isalpha() and body[2:].isdigit():
|
|
139
|
+
return raw
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f"Invalid PCT application format: {input_number}. "
|
|
142
|
+
"Expected PCT/CCYYYY/NNNNNN or PCTCCYYYYNNNNNN."
|
|
143
|
+
)
|
|
133
144
|
if len(parts) != 3:
|
|
134
145
|
raise ValueError(
|
|
135
146
|
f"Invalid PCT application format: {input_number}. "
|
|
@@ -140,6 +151,10 @@ class PatentDataClient(BaseUSPTOClient[PatentDataResponse]):
|
|
|
140
151
|
|
|
141
152
|
# country_year can be "US2024" or "US24"
|
|
142
153
|
country = country_year[:2]
|
|
154
|
+
if len(country) != 2 or not country.isalpha():
|
|
155
|
+
raise ValueError(
|
|
156
|
+
f"Invalid PCT country code in: {country_year}. Expected 2 letters."
|
|
157
|
+
)
|
|
143
158
|
|
|
144
159
|
year_part = country_year[2:]
|
|
145
160
|
if not year_part.isdigit():
|
|
@@ -147,24 +162,28 @@ class PatentDataClient(BaseUSPTOClient[PatentDataResponse]):
|
|
|
147
162
|
f"Invalid PCT year in: {country_year}. Must be digits."
|
|
148
163
|
)
|
|
149
164
|
|
|
150
|
-
# Normalize
|
|
151
|
-
#
|
|
152
|
-
# "24" -> "24"
|
|
165
|
+
# Normalize to 4-digit year. 2-digit input uses a sliding window
|
|
166
|
+
# tied to the PCT system's start year (1978): YY>=78 -> 19YY, else 20YY.
|
|
153
167
|
if len(year_part) == 4:
|
|
154
|
-
year = year_part[-2:]
|
|
155
|
-
elif len(year_part) == 2:
|
|
156
168
|
year = year_part
|
|
169
|
+
elif len(year_part) == 2:
|
|
170
|
+
yy = int(year_part)
|
|
171
|
+
year = f"19{year_part}" if yy >= 78 else f"20{year_part}"
|
|
157
172
|
else:
|
|
158
173
|
raise ValueError(
|
|
159
174
|
f"Invalid PCT year length in: {country_year}. "
|
|
160
175
|
"Expected CCYYYY or CCYY."
|
|
161
176
|
)
|
|
162
177
|
|
|
163
|
-
# Serial must be digits only
|
|
178
|
+
# Serial must be digits only, and fit in 6 digits.
|
|
164
179
|
if not serial.isdigit():
|
|
165
180
|
raise ValueError(f"Invalid PCT serial: {serial}. Must be numeric.")
|
|
181
|
+
if len(serial) > 6:
|
|
182
|
+
raise ValueError(
|
|
183
|
+
f"Invalid PCT serial: {serial}. Must be at most 6 digits."
|
|
184
|
+
)
|
|
166
185
|
|
|
167
|
-
return f"PCT{country}{year}{serial.
|
|
186
|
+
return f"PCT{country}{year}{serial.zfill(6)}"
|
|
168
187
|
|
|
169
188
|
# Strip whitespace and remove commas/spaces
|
|
170
189
|
cleaned = raw.replace(",", "").replace(" ", "")
|
|
@@ -5,7 +5,7 @@ including API keys, base URLs, and HTTP transport settings.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
11
|
import requests
|
|
@@ -15,6 +15,36 @@ from pyUSPTO.http_config import HTTPConfig
|
|
|
15
15
|
DEFAULT_BASE_URL = "https://api.uspto.gov"
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def _env_values() -> dict[str, Any]:
|
|
19
|
+
"""Build a dict of config values from environment variables (or defaults)."""
|
|
20
|
+
return {
|
|
21
|
+
"api_key": os.environ.get("USPTO_API_KEY") or None,
|
|
22
|
+
"bulk_data_base_url": os.environ.get(
|
|
23
|
+
"USPTO_BULK_DATA_BASE_URL", DEFAULT_BASE_URL
|
|
24
|
+
),
|
|
25
|
+
"patent_data_base_url": os.environ.get(
|
|
26
|
+
"USPTO_PATENT_DATA_BASE_URL", DEFAULT_BASE_URL
|
|
27
|
+
),
|
|
28
|
+
"petition_decisions_base_url": os.environ.get(
|
|
29
|
+
"USPTO_PETITION_DECISIONS_BASE_URL", DEFAULT_BASE_URL
|
|
30
|
+
),
|
|
31
|
+
"ptab_base_url": os.environ.get("USPTO_PTAB_BASE_URL", DEFAULT_BASE_URL),
|
|
32
|
+
"enriched_citations_base_url": os.environ.get(
|
|
33
|
+
"USPTO_ENRICHED_CITATIONS_BASE_URL", DEFAULT_BASE_URL
|
|
34
|
+
),
|
|
35
|
+
"oa_actions_base_url": os.environ.get(
|
|
36
|
+
"USPTO_OA_ACTIONS_BASE_URL", DEFAULT_BASE_URL
|
|
37
|
+
),
|
|
38
|
+
"oa_rejections_base_url": os.environ.get(
|
|
39
|
+
"USPTO_OA_REJECTIONS_BASE_URL", DEFAULT_BASE_URL
|
|
40
|
+
),
|
|
41
|
+
"oa_citations_base_url": os.environ.get(
|
|
42
|
+
"USPTO_OA_CITATIONS_BASE_URL", DEFAULT_BASE_URL
|
|
43
|
+
),
|
|
44
|
+
"http_config": HTTPConfig.from_env(),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
18
48
|
class USPTOConfig:
|
|
19
49
|
"""Configuration for USPTO API clients.
|
|
20
50
|
|
|
@@ -25,19 +55,22 @@ class USPTOConfig:
|
|
|
25
55
|
def __init__(
|
|
26
56
|
self,
|
|
27
57
|
api_key: str | None = None,
|
|
28
|
-
bulk_data_base_url: str =
|
|
29
|
-
patent_data_base_url: str =
|
|
30
|
-
petition_decisions_base_url: str =
|
|
31
|
-
ptab_base_url: str =
|
|
32
|
-
enriched_citations_base_url: str =
|
|
33
|
-
oa_actions_base_url: str =
|
|
34
|
-
oa_rejections_base_url: str =
|
|
35
|
-
oa_citations_base_url: str =
|
|
58
|
+
bulk_data_base_url: str | None = None,
|
|
59
|
+
patent_data_base_url: str | None = None,
|
|
60
|
+
petition_decisions_base_url: str | None = None,
|
|
61
|
+
ptab_base_url: str | None = None,
|
|
62
|
+
enriched_citations_base_url: str | None = None,
|
|
63
|
+
oa_actions_base_url: str | None = None,
|
|
64
|
+
oa_rejections_base_url: str | None = None,
|
|
65
|
+
oa_citations_base_url: str | None = None,
|
|
36
66
|
http_config: HTTPConfig | None = None,
|
|
37
67
|
include_raw_data: bool = False,
|
|
38
68
|
):
|
|
39
69
|
"""Initialize the USPTOConfig.
|
|
40
70
|
|
|
71
|
+
Each field falls back to its environment variable (or the package
|
|
72
|
+
default) when the caller does not pass a value.
|
|
73
|
+
|
|
41
74
|
Args:
|
|
42
75
|
api_key: API key for authentication, defaults to USPTO_API_KEY environment variable
|
|
43
76
|
bulk_data_base_url: Base URL for the Bulk Data API
|
|
@@ -51,21 +84,43 @@ class USPTOConfig:
|
|
|
51
84
|
http_config: Optional HTTPConfig for request handling (uses defaults if None)
|
|
52
85
|
include_raw_data: If True, store raw JSON in response objects for debugging (default: False)
|
|
53
86
|
"""
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
87
|
+
env = _env_values()
|
|
88
|
+
|
|
89
|
+
self.api_key = api_key if api_key else env["api_key"]
|
|
90
|
+
self.bulk_data_base_url = (
|
|
91
|
+
bulk_data_base_url if bulk_data_base_url else env["bulk_data_base_url"]
|
|
92
|
+
)
|
|
93
|
+
self.patent_data_base_url = (
|
|
94
|
+
patent_data_base_url
|
|
95
|
+
if patent_data_base_url
|
|
96
|
+
else env["patent_data_base_url"]
|
|
97
|
+
)
|
|
98
|
+
self.petition_decisions_base_url = (
|
|
99
|
+
petition_decisions_base_url
|
|
100
|
+
if petition_decisions_base_url
|
|
101
|
+
else env["petition_decisions_base_url"]
|
|
57
102
|
)
|
|
58
|
-
self.
|
|
59
|
-
self.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
self.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
103
|
+
self.ptab_base_url = ptab_base_url if ptab_base_url else env["ptab_base_url"]
|
|
104
|
+
self.enriched_citations_base_url = (
|
|
105
|
+
enriched_citations_base_url
|
|
106
|
+
if enriched_citations_base_url
|
|
107
|
+
else env["enriched_citations_base_url"]
|
|
108
|
+
)
|
|
109
|
+
self.oa_actions_base_url = (
|
|
110
|
+
oa_actions_base_url if oa_actions_base_url else env["oa_actions_base_url"]
|
|
111
|
+
)
|
|
112
|
+
self.oa_rejections_base_url = (
|
|
113
|
+
oa_rejections_base_url
|
|
114
|
+
if oa_rejections_base_url
|
|
115
|
+
else env["oa_rejections_base_url"]
|
|
116
|
+
)
|
|
117
|
+
self.oa_citations_base_url = (
|
|
118
|
+
oa_citations_base_url
|
|
119
|
+
if oa_citations_base_url
|
|
120
|
+
else env["oa_citations_base_url"]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
self.http_config = http_config if http_config else env["http_config"]
|
|
69
124
|
|
|
70
125
|
# Control whether to include raw JSON data in response objects
|
|
71
126
|
self.include_raw_data = include_raw_data
|
|
@@ -80,33 +135,7 @@ class USPTOConfig:
|
|
|
80
135
|
Returns:
|
|
81
136
|
USPTOConfig instance with values from environment
|
|
82
137
|
"""
|
|
83
|
-
return cls(
|
|
84
|
-
api_key=os.environ.get("USPTO_API_KEY"),
|
|
85
|
-
bulk_data_base_url=os.environ.get(
|
|
86
|
-
"USPTO_BULK_DATA_BASE_URL", DEFAULT_BASE_URL
|
|
87
|
-
),
|
|
88
|
-
patent_data_base_url=os.environ.get(
|
|
89
|
-
"USPTO_PATENT_DATA_BASE_URL", DEFAULT_BASE_URL
|
|
90
|
-
),
|
|
91
|
-
petition_decisions_base_url=os.environ.get(
|
|
92
|
-
"USPTO_PETITION_DECISIONS_BASE_URL", DEFAULT_BASE_URL
|
|
93
|
-
),
|
|
94
|
-
ptab_base_url=os.environ.get("USPTO_PTAB_BASE_URL", DEFAULT_BASE_URL),
|
|
95
|
-
enriched_citations_base_url=os.environ.get(
|
|
96
|
-
"USPTO_ENRICHED_CITATIONS_BASE_URL", DEFAULT_BASE_URL
|
|
97
|
-
),
|
|
98
|
-
oa_actions_base_url=os.environ.get(
|
|
99
|
-
"USPTO_OA_ACTIONS_BASE_URL", DEFAULT_BASE_URL
|
|
100
|
-
),
|
|
101
|
-
oa_rejections_base_url=os.environ.get(
|
|
102
|
-
"USPTO_OA_REJECTIONS_BASE_URL", DEFAULT_BASE_URL
|
|
103
|
-
),
|
|
104
|
-
oa_citations_base_url=os.environ.get(
|
|
105
|
-
"USPTO_OA_CITATIONS_BASE_URL", DEFAULT_BASE_URL
|
|
106
|
-
),
|
|
107
|
-
# Also read HTTP config from environment
|
|
108
|
-
http_config=HTTPConfig.from_env(),
|
|
109
|
-
)
|
|
138
|
+
return cls(**_env_values())
|
|
110
139
|
|
|
111
140
|
@property
|
|
112
141
|
def session(self) -> "requests.Session":
|
|
@@ -480,7 +480,11 @@ class Address:
|
|
|
480
480
|
country_name: Full name of the country (e.g., "United States").
|
|
481
481
|
postal_address_category: Category of the address (e.g., "MAILING_ADDRESS").
|
|
482
482
|
correspondent_name_text: Name of the correspondent at this address.
|
|
483
|
-
country_or_state_code: Country or state code.
|
|
483
|
+
country_or_state_code: Country or state code. Deprecated: USPTO ODP
|
|
484
|
+
Release 3.6 (2026-04-10) removed this field from the Patent
|
|
485
|
+
Assignment API response. Read ``geographic_region_code`` instead;
|
|
486
|
+
this attribute will be ``None`` for responses from updated
|
|
487
|
+
endpoints.
|
|
484
488
|
ict_state_code: International code for the state/region (USPTO format).
|
|
485
489
|
ict_country_code: International code for the country (USPTO format).
|
|
486
490
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyUSPTO
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: A Modern Python client for accessing the United States Patent and Trademark Office (USPTO) Open Data Portal (ODP) APIs.
|
|
5
5
|
Author-email: Andrew Piechocki <apiechocki@dunlapcodding.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -201,7 +201,7 @@ if app.application_meta_data:
|
|
|
201
201
|
wrapper = client.get_IFW_metadata(application_number="18/045,436")
|
|
202
202
|
wrapper = client.get_IFW_metadata(patent_number="11,234,567")
|
|
203
203
|
wrapper = client.get_IFW_metadata(publication_number="2023/0012345")
|
|
204
|
-
wrapper = client.get_IFW_metadata(PCT_app_number="PCT/
|
|
204
|
+
wrapper = client.get_IFW_metadata(PCT_app_number="PCT/US2024/012345")
|
|
205
205
|
|
|
206
206
|
# Look up USPTO status codes
|
|
207
207
|
status_codes = client.get_status_codes()
|
|
@@ -1133,9 +1133,7 @@ class TestPaginateSolrResults:
|
|
|
1133
1133
|
|
|
1134
1134
|
received_bodies: list[dict[str, Any]] = []
|
|
1135
1135
|
|
|
1136
|
-
def mock_search(
|
|
1137
|
-
post_body: dict[str, Any] | None = None, **kwargs: Any
|
|
1138
|
-
) -> Any:
|
|
1136
|
+
def mock_search(post_body: dict[str, Any] | None = None, **kwargs: Any) -> Any:
|
|
1139
1137
|
if post_body:
|
|
1140
1138
|
received_bodies.append(post_body.copy())
|
|
1141
1139
|
start = post_body["start"] if post_body else 0
|
|
@@ -1183,9 +1181,7 @@ class TestPaginateSolrResults:
|
|
|
1183
1181
|
test_client = TestClient(base_url="https://api.test.com")
|
|
1184
1182
|
test_client.config._session = mock_session
|
|
1185
1183
|
|
|
1186
|
-
with patch.object(
|
|
1187
|
-
test_client, "search", wraps=test_client.search
|
|
1188
|
-
) as spy:
|
|
1184
|
+
with patch.object(test_client, "search", wraps=test_client.search) as spy:
|
|
1189
1185
|
results = list(
|
|
1190
1186
|
test_client.paginate_solr_results(
|
|
1191
1187
|
method_name="search",
|
|
@@ -1198,9 +1194,7 @@ class TestPaginateSolrResults:
|
|
|
1198
1194
|
assert results == ["doc1"]
|
|
1199
1195
|
spy.assert_called_once_with(query="test", start=0, rows=10)
|
|
1200
1196
|
|
|
1201
|
-
def test_paginate_solr_results_custom_rows(
|
|
1202
|
-
self, mock_session: MagicMock
|
|
1203
|
-
) -> None:
|
|
1197
|
+
def test_paginate_solr_results_custom_rows(self, mock_session: MagicMock) -> None:
|
|
1204
1198
|
"""Test that rows is extracted from post_body and used as page size."""
|
|
1205
1199
|
response = MagicMock()
|
|
1206
1200
|
response.count = 1
|
|
@@ -1208,9 +1202,7 @@ class TestPaginateSolrResults:
|
|
|
1208
1202
|
|
|
1209
1203
|
received_bodies: list[dict[str, Any]] = []
|
|
1210
1204
|
|
|
1211
|
-
def mock_search(
|
|
1212
|
-
post_body: dict[str, Any] | None = None, **kwargs: Any
|
|
1213
|
-
) -> Any:
|
|
1205
|
+
def mock_search(post_body: dict[str, Any] | None = None, **kwargs: Any) -> Any:
|
|
1214
1206
|
if post_body:
|
|
1215
1207
|
received_bodies.append(post_body.copy())
|
|
1216
1208
|
return response
|
|
@@ -1231,9 +1223,7 @@ class TestPaginateSolrResults:
|
|
|
1231
1223
|
assert received_bodies[0]["rows"] == 100
|
|
1232
1224
|
assert received_bodies[0]["start"] == 0
|
|
1233
1225
|
|
|
1234
|
-
def test_paginate_solr_results_default_rows(
|
|
1235
|
-
self, mock_session: MagicMock
|
|
1236
|
-
) -> None:
|
|
1226
|
+
def test_paginate_solr_results_default_rows(self, mock_session: MagicMock) -> None:
|
|
1237
1227
|
"""Test that rows defaults to 25 when not specified."""
|
|
1238
1228
|
response = MagicMock()
|
|
1239
1229
|
response.count = 1
|
|
@@ -1241,9 +1231,7 @@ class TestPaginateSolrResults:
|
|
|
1241
1231
|
|
|
1242
1232
|
received_bodies: list[dict[str, Any]] = []
|
|
1243
1233
|
|
|
1244
|
-
def mock_search(
|
|
1245
|
-
post_body: dict[str, Any] | None = None, **kwargs: Any
|
|
1246
|
-
) -> Any:
|
|
1234
|
+
def mock_search(post_body: dict[str, Any] | None = None, **kwargs: Any) -> Any:
|
|
1247
1235
|
if post_body:
|
|
1248
1236
|
received_bodies.append(post_body.copy())
|
|
1249
1237
|
return response
|
|
@@ -1271,9 +1259,7 @@ class TestPaginateSolrResults:
|
|
|
1271
1259
|
|
|
1272
1260
|
post_body = {"criteria": "test", "start": 10, "rows": 50}
|
|
1273
1261
|
|
|
1274
|
-
with pytest.raises(
|
|
1275
|
-
ValueError, match="Cannot specify 'start' in post_body"
|
|
1276
|
-
):
|
|
1262
|
+
with pytest.raises(ValueError, match="Cannot specify 'start' in post_body"):
|
|
1277
1263
|
list(
|
|
1278
1264
|
client.paginate_solr_results(
|
|
1279
1265
|
method_name="search",
|
|
@@ -1289,9 +1275,7 @@ class TestPaginateSolrResults:
|
|
|
1289
1275
|
client: BaseUSPTOClient[Any] = BaseUSPTOClient(base_url="https://api.test.com")
|
|
1290
1276
|
client.config._session = mock_session
|
|
1291
1277
|
|
|
1292
|
-
with pytest.raises(
|
|
1293
|
-
ValueError, match="Cannot specify 'start' in kwargs"
|
|
1294
|
-
):
|
|
1278
|
+
with pytest.raises(ValueError, match="Cannot specify 'start' in kwargs"):
|
|
1295
1279
|
list(
|
|
1296
1280
|
client.paginate_solr_results(
|
|
1297
1281
|
method_name="search",
|
|
@@ -1353,9 +1337,7 @@ class TestPaginateSolrResults:
|
|
|
1353
1337
|
|
|
1354
1338
|
received_bodies: list[dict[str, Any]] = []
|
|
1355
1339
|
|
|
1356
|
-
def mock_search(
|
|
1357
|
-
post_body: dict[str, Any] | None = None, **kwargs: Any
|
|
1358
|
-
) -> Any:
|
|
1340
|
+
def mock_search(post_body: dict[str, Any] | None = None, **kwargs: Any) -> Any:
|
|
1359
1341
|
if post_body:
|
|
1360
1342
|
received_bodies.append(post_body.copy())
|
|
1361
1343
|
return response
|
|
@@ -182,8 +182,7 @@ class TestOACitationsClientSearch:
|
|
|
182
182
|
|
|
183
183
|
call_kwargs = mock_get_model.call_args.kwargs
|
|
184
184
|
assert (
|
|
185
|
-
call_kwargs["json_data"]["criteria"]
|
|
186
|
-
== "patentApplicationNumber:17519936"
|
|
185
|
+
call_kwargs["json_data"]["criteria"] == "patentApplicationNumber:17519936"
|
|
187
186
|
)
|
|
188
187
|
|
|
189
188
|
def test_legal_section_code_q(
|
|
@@ -313,9 +312,7 @@ class TestOACitationsClientSearch:
|
|
|
313
312
|
client.search(create_date_time_from_q="2025-01-01")
|
|
314
313
|
|
|
315
314
|
call_kwargs = mock_get_model.call_args.kwargs
|
|
316
|
-
assert
|
|
317
|
-
call_kwargs["json_data"]["criteria"] == "createDateTime:>=2025-01-01"
|
|
318
|
-
)
|
|
315
|
+
assert call_kwargs["json_data"]["criteria"] == "createDateTime:>=2025-01-01"
|
|
319
316
|
|
|
320
317
|
def test_create_date_time_to_only(
|
|
321
318
|
self,
|
|
@@ -328,9 +325,7 @@ class TestOACitationsClientSearch:
|
|
|
328
325
|
client.search(create_date_time_to_q="2025-06-30")
|
|
329
326
|
|
|
330
327
|
call_kwargs = mock_get_model.call_args.kwargs
|
|
331
|
-
assert
|
|
332
|
-
call_kwargs["json_data"]["criteria"] == "createDateTime:<=2025-06-30"
|
|
333
|
-
)
|
|
328
|
+
assert call_kwargs["json_data"]["criteria"] == "createDateTime:<=2025-06-30"
|
|
334
329
|
|
|
335
330
|
def test_combined_convenience_params(
|
|
336
331
|
self,
|
|
@@ -457,9 +452,7 @@ class TestOACitationsClientPaginate:
|
|
|
457
452
|
rows=10,
|
|
458
453
|
)
|
|
459
454
|
|
|
460
|
-
def test_passes_post_body(
|
|
461
|
-
self, oa_citations_client: OACitationsClient
|
|
462
|
-
) -> None:
|
|
455
|
+
def test_passes_post_body(self, oa_citations_client: OACitationsClient) -> None:
|
|
463
456
|
with patch.object(
|
|
464
457
|
oa_citations_client, "paginate_solr_results", autospec=True
|
|
465
458
|
) as mock_paginate:
|
|
@@ -479,9 +472,7 @@ class TestOACitationsClientPaginate:
|
|
|
479
472
|
mock_record: OACitationRecord,
|
|
480
473
|
mock_response_with_data: OACitationsResponse,
|
|
481
474
|
) -> None:
|
|
482
|
-
with patch.object(
|
|
483
|
-
oa_citations_client, "search", autospec=True
|
|
484
|
-
) as mock_search:
|
|
475
|
+
with patch.object(oa_citations_client, "search", autospec=True) as mock_search:
|
|
485
476
|
# Two pages: first has data, second is empty to stop pagination
|
|
486
477
|
mock_search.side_effect = [
|
|
487
478
|
mock_response_with_data,
|
|
@@ -399,7 +399,9 @@ class TestOARejectionsClientPaginate:
|
|
|
399
399
|
oa_rejections_client, "paginate_solr_results", autospec=True
|
|
400
400
|
) as mock_paginate:
|
|
401
401
|
mock_paginate.return_value = iter([])
|
|
402
|
-
oa_rejections_client.paginate(
|
|
402
|
+
oa_rejections_client.paginate(
|
|
403
|
+
legacy_document_code_identifier_q="CTNF", rows=10
|
|
404
|
+
)
|
|
403
405
|
|
|
404
406
|
mock_paginate.assert_called_once_with(
|
|
405
407
|
method_name="search",
|
|
@@ -429,9 +431,7 @@ class TestOARejectionsClientPaginate:
|
|
|
429
431
|
mock_record: OARejectionsRecord,
|
|
430
432
|
mock_response_with_data: OARejectionsResponse,
|
|
431
433
|
) -> None:
|
|
432
|
-
with patch.object(
|
|
433
|
-
oa_rejections_client, "search", autospec=True
|
|
434
|
-
) as mock_search:
|
|
434
|
+
with patch.object(oa_rejections_client, "search", autospec=True) as mock_search:
|
|
435
435
|
mock_search.side_effect = [
|
|
436
436
|
mock_response_with_data,
|
|
437
437
|
OARejectionsResponse(num_found=0, start=0, docs=[]),
|