pdfdata-api 0.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.
- pdfdata_api-0.2.0/LICENSE.txt +31 -0
- pdfdata_api-0.2.0/PDFData_API.py +4 -0
- pdfdata_api-0.2.0/PKG-INFO +84 -0
- pdfdata_api-0.2.0/README.md +69 -0
- pdfdata_api-0.2.0/pdfdata_api/__init__.py +5 -0
- pdfdata_api-0.2.0/pdfdata_api/client.py +143 -0
- pdfdata_api-0.2.0/pdfdata_api.egg-info/PKG-INFO +84 -0
- pdfdata_api-0.2.0/pdfdata_api.egg-info/SOURCES.txt +12 -0
- pdfdata_api-0.2.0/pdfdata_api.egg-info/dependency_links.txt +1 -0
- pdfdata_api-0.2.0/pdfdata_api.egg-info/requires.txt +1 -0
- pdfdata_api-0.2.0/pdfdata_api.egg-info/top_level.txt +2 -0
- pdfdata_api-0.2.0/pyproject.toml +23 -0
- pdfdata_api-0.2.0/setup.cfg +4 -0
- pdfdata_api-0.2.0/setup.py +5 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022, yanglonggroup
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
30
|
+
|
|
31
|
+
For more information please email Prof. Long Yang at long_yang@tongji.edu.cn
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdfdata-api
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python client for the PDFData materials database API
|
|
5
|
+
Author-email: PDF Database Team <contact@pdfdata.org>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://pdfdata.org
|
|
8
|
+
Project-URL: Documentation, https://pdfdata.org/documents/api
|
|
9
|
+
Project-URL: Source, https://github.com/yanglonggroup/pdfDBflask
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE.txt
|
|
13
|
+
Requires-Dist: requests>=2.25.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# PDFData Python client
|
|
17
|
+
|
|
18
|
+
Standalone client for `https://pdfdata.org/api/v1`. Requires Python 3.9+ and
|
|
19
|
+
`requests`; Flask, MongoDB and scientific packages are not client dependencies.
|
|
20
|
+
Version 0.2.0 source and build configuration are in this repository. A public
|
|
21
|
+
PyPI release has not been made as part of this change.
|
|
22
|
+
|
|
23
|
+
Install from a local checkout (repository root):
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
python -m pip install ./src/pdfdb_backend
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or install the built wheel supplied with a release:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
python -m pip install /path/to/pdfdata_api-0.2.0-py3-none-any.whl
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Generate a key on the website's API page after signing in. Set it in an
|
|
36
|
+
environment variable and query:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import os
|
|
40
|
+
from pdfdata_api import PDFData_API
|
|
41
|
+
|
|
42
|
+
with PDFData_API(api_key=os.environ["PDFDATA_API_KEY"]) as client:
|
|
43
|
+
page = client.get_materials(elements="Si,O", per_page=20)
|
|
44
|
+
material = client.get_material("mp-10009-X")
|
|
45
|
+
curve = client.get_pdf_data("mp-10009-X")
|
|
46
|
+
all_matches = client.get_all_materials(elements="Si,O")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`get_materials()` and `search()` return one page by default. Page size is 1–100.
|
|
50
|
+
`get_all_materials()` and `search_all()` collect successive pages. Legacy client
|
|
51
|
+
calls with `per_page=0` also collect successive pages; direct HTTP requests must
|
|
52
|
+
use page sizes 1–100. Collection is not a database snapshot while data changes.
|
|
53
|
+
|
|
54
|
+
Advanced search:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
result = client.search({
|
|
58
|
+
"elements": {"all": ["Si"], "none": ["Au"]},
|
|
59
|
+
"qmax": "[10,30]",
|
|
60
|
+
"page": 1,
|
|
61
|
+
"per_page": 20,
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For applications already holding a website **access JWT**, `PDFData_API()` can
|
|
66
|
+
call `generate_api_key(jwt_token)`, `get_api_keys(jwt_token)` and
|
|
67
|
+
`delete_api_key(jwt_token, "Key 1")`. The generated key is set on the client.
|
|
68
|
+
Key management requires the login JWT; material queries require the API key.
|
|
69
|
+
`generate_api_key` creates a new key on each call and is not automatically retried.
|
|
70
|
+
|
|
71
|
+
`MaterialsAPI` remains an alias of `PDFData_API`. The old import
|
|
72
|
+
`from PDFData_API import PDFData_API` remains supported. Backend source imports
|
|
73
|
+
`from app.api.client import MaterialsAPI` forward to the same implementation.
|
|
74
|
+
The default timeout is 30 seconds and can be set with `timeout=60`. HTTP errors
|
|
75
|
+
raise `requests.HTTPError`; inspect `exc.response.status_code` and JSON `code`.
|
|
76
|
+
|
|
77
|
+
Build from this directory:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
python -m build
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Only `pdfdata_api` and the legacy `PDFData_API` module are included in the
|
|
84
|
+
distribution. Production environment files and backend code are excluded.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# PDFData Python client
|
|
2
|
+
|
|
3
|
+
Standalone client for `https://pdfdata.org/api/v1`. Requires Python 3.9+ and
|
|
4
|
+
`requests`; Flask, MongoDB and scientific packages are not client dependencies.
|
|
5
|
+
Version 0.2.0 source and build configuration are in this repository. A public
|
|
6
|
+
PyPI release has not been made as part of this change.
|
|
7
|
+
|
|
8
|
+
Install from a local checkout (repository root):
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
python -m pip install ./src/pdfdb_backend
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or install the built wheel supplied with a release:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
python -m pip install /path/to/pdfdata_api-0.2.0-py3-none-any.whl
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Generate a key on the website's API page after signing in. Set it in an
|
|
21
|
+
environment variable and query:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import os
|
|
25
|
+
from pdfdata_api import PDFData_API
|
|
26
|
+
|
|
27
|
+
with PDFData_API(api_key=os.environ["PDFDATA_API_KEY"]) as client:
|
|
28
|
+
page = client.get_materials(elements="Si,O", per_page=20)
|
|
29
|
+
material = client.get_material("mp-10009-X")
|
|
30
|
+
curve = client.get_pdf_data("mp-10009-X")
|
|
31
|
+
all_matches = client.get_all_materials(elements="Si,O")
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`get_materials()` and `search()` return one page by default. Page size is 1–100.
|
|
35
|
+
`get_all_materials()` and `search_all()` collect successive pages. Legacy client
|
|
36
|
+
calls with `per_page=0` also collect successive pages; direct HTTP requests must
|
|
37
|
+
use page sizes 1–100. Collection is not a database snapshot while data changes.
|
|
38
|
+
|
|
39
|
+
Advanced search:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
result = client.search({
|
|
43
|
+
"elements": {"all": ["Si"], "none": ["Au"]},
|
|
44
|
+
"qmax": "[10,30]",
|
|
45
|
+
"page": 1,
|
|
46
|
+
"per_page": 20,
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For applications already holding a website **access JWT**, `PDFData_API()` can
|
|
51
|
+
call `generate_api_key(jwt_token)`, `get_api_keys(jwt_token)` and
|
|
52
|
+
`delete_api_key(jwt_token, "Key 1")`. The generated key is set on the client.
|
|
53
|
+
Key management requires the login JWT; material queries require the API key.
|
|
54
|
+
`generate_api_key` creates a new key on each call and is not automatically retried.
|
|
55
|
+
|
|
56
|
+
`MaterialsAPI` remains an alias of `PDFData_API`. The old import
|
|
57
|
+
`from PDFData_API import PDFData_API` remains supported. Backend source imports
|
|
58
|
+
`from app.api.client import MaterialsAPI` forward to the same implementation.
|
|
59
|
+
The default timeout is 30 seconds and can be set with `timeout=60`. HTTP errors
|
|
60
|
+
raise `requests.HTTPError`; inspect `exc.response.status_code` and JSON `code`.
|
|
61
|
+
|
|
62
|
+
Build from this directory:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
python -m build
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Only `pdfdata_api` and the legacy `PDFData_API` module are included in the
|
|
69
|
+
distribution. Production environment files and backend code are excluded.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""One implementation for the public client and legacy import paths."""
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
import math
|
|
5
|
+
from urllib.parse import urlsplit
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__version__ = "0.2.0"
|
|
11
|
+
DEFAULT_BASE_URL = "https://pdfdata.org/api/v1"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PDFData_API:
|
|
15
|
+
"""Query public materials with an API key; manage keys with a login JWT."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, api_key=None, base_url=DEFAULT_BASE_URL, *, timeout=30, session=None):
|
|
18
|
+
parsed = urlsplit(base_url)
|
|
19
|
+
if parsed.scheme not in {"http", "https"} or not parsed.netloc or parsed.query or parsed.fragment:
|
|
20
|
+
raise ValueError("base_url must be an HTTP(S) API URL without a query or fragment")
|
|
21
|
+
if parsed.username or parsed.password:
|
|
22
|
+
raise ValueError("base_url must not contain credentials")
|
|
23
|
+
if isinstance(timeout, bool) or not isinstance(timeout, (int, float)) or not math.isfinite(timeout) or timeout <= 0:
|
|
24
|
+
raise ValueError("timeout must be a positive, finite number of seconds")
|
|
25
|
+
self.base_url = base_url.rstrip("/")
|
|
26
|
+
self.timeout = timeout
|
|
27
|
+
self._session = session if session is not None else requests.Session()
|
|
28
|
+
self.api_key = api_key
|
|
29
|
+
self.headers = {"Content-Type": "application/json",
|
|
30
|
+
"User-Agent": f"PDFData-Python-Client/{__version__}"}
|
|
31
|
+
if api_key is not None:
|
|
32
|
+
self._key(api_key)
|
|
33
|
+
self.headers["Authorization"] = f"Bearer {api_key}"
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _key(value):
|
|
37
|
+
if not isinstance(value, str) or not value or len(value) > 512 or any(c.isspace() for c in value):
|
|
38
|
+
raise ValueError("A non-empty API key is required")
|
|
39
|
+
return value
|
|
40
|
+
|
|
41
|
+
def _request(self, method, path, *, params=None, body=None, jwt_token=None):
|
|
42
|
+
headers = dict(self.headers)
|
|
43
|
+
if jwt_token is not None:
|
|
44
|
+
if not isinstance(jwt_token, str) or not jwt_token or any(c.isspace() for c in jwt_token):
|
|
45
|
+
raise ValueError("A login access JWT is required")
|
|
46
|
+
headers["Authorization"] = f"Bearer {jwt_token}"
|
|
47
|
+
else:
|
|
48
|
+
headers["Authorization"] = f"Bearer {self._key(self.api_key)}"
|
|
49
|
+
response = self._session.request(method, f"{self.base_url}{path}", headers=headers,
|
|
50
|
+
params=params, json=body, timeout=self.timeout)
|
|
51
|
+
response.raise_for_status()
|
|
52
|
+
return response.json()
|
|
53
|
+
|
|
54
|
+
def get_materials(self, page=1, per_page=20, **filters):
|
|
55
|
+
"""One page (1..100 items); legacy per_page=0 uses automatic pagination."""
|
|
56
|
+
if per_page == 0 and not isinstance(per_page, bool):
|
|
57
|
+
if not filters.get("detail") and filters.get("data_type") is None:
|
|
58
|
+
return self.get_all_materials(**filters)
|
|
59
|
+
per_page = 20
|
|
60
|
+
return self._request("GET", "/materials/search",
|
|
61
|
+
params={"page": page, "per_page": per_page, **filters})
|
|
62
|
+
|
|
63
|
+
def get_material(self, material_id):
|
|
64
|
+
return self.get_materials(material_id=material_id, detail="true")
|
|
65
|
+
|
|
66
|
+
def get_pdf_data(self, material_id):
|
|
67
|
+
return self.get_data(material_id, "pdf")
|
|
68
|
+
|
|
69
|
+
def get_data(self, material_id, data_type):
|
|
70
|
+
return self.get_materials(material_id=material_id, data_type=data_type)
|
|
71
|
+
|
|
72
|
+
def search(self, criteria):
|
|
73
|
+
"""Advanced POST search; the caller's criteria are never modified."""
|
|
74
|
+
if not isinstance(criteria, dict):
|
|
75
|
+
raise ValueError("criteria must be a dictionary")
|
|
76
|
+
criteria = deepcopy(criteria)
|
|
77
|
+
if criteria.get("per_page") == 0 and not isinstance(criteria.get("per_page"), bool):
|
|
78
|
+
if not criteria.get("detail") and criteria.get("data_type") is None:
|
|
79
|
+
return self.search_all(criteria)
|
|
80
|
+
criteria["per_page"] = 20
|
|
81
|
+
return self._request("POST", "/materials/search", body=criteria)
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def _collect(fetch):
|
|
85
|
+
first = fetch(1)
|
|
86
|
+
if not isinstance(first.get("materials"), list):
|
|
87
|
+
# Legacy calls combining get_all with detail/data_type return one object.
|
|
88
|
+
return first
|
|
89
|
+
rows = list(first["materials"])
|
|
90
|
+
for page in range(2, first["pages"] + 1):
|
|
91
|
+
response = fetch(page)
|
|
92
|
+
rows.extend(response["materials"])
|
|
93
|
+
if not response["materials"]:
|
|
94
|
+
break
|
|
95
|
+
return {"materials": rows, "total": first["total"], "returned": len(rows),
|
|
96
|
+
"query": first.get("query", {})}
|
|
97
|
+
|
|
98
|
+
def get_all_materials(self, **filters):
|
|
99
|
+
"""Fetch every page with bounded requests; datasets are not snapshot-isolated."""
|
|
100
|
+
filters = deepcopy(filters)
|
|
101
|
+
filters.pop("page", None)
|
|
102
|
+
filters.pop("per_page", None)
|
|
103
|
+
return self._collect(lambda page: self.get_materials(page=page, per_page=100, **filters))
|
|
104
|
+
|
|
105
|
+
def search_all(self, criteria):
|
|
106
|
+
if not isinstance(criteria, dict):
|
|
107
|
+
raise ValueError("criteria must be a dictionary")
|
|
108
|
+
criteria = deepcopy(criteria)
|
|
109
|
+
criteria["per_page"] = 100
|
|
110
|
+
return self._collect(lambda page: self.search({**criteria, "page": page}))
|
|
111
|
+
|
|
112
|
+
def generate_api_key(self, jwt_token):
|
|
113
|
+
"""Works on PDFData_API() before the user has their first API key."""
|
|
114
|
+
if jwt_token is None:
|
|
115
|
+
raise ValueError("A login access JWT is required")
|
|
116
|
+
result = self._request("POST", "/user/create_key", jwt_token=jwt_token)
|
|
117
|
+
self.api_key = result["api_key"]
|
|
118
|
+
self.headers["Authorization"] = f"Bearer {self.api_key}"
|
|
119
|
+
return result
|
|
120
|
+
|
|
121
|
+
def get_api_keys(self, jwt_token):
|
|
122
|
+
if jwt_token is None:
|
|
123
|
+
raise ValueError("A login access JWT is required")
|
|
124
|
+
return self._request("GET", "/user/get_keys", jwt_token=jwt_token)
|
|
125
|
+
|
|
126
|
+
def delete_api_key(self, jwt_token, label):
|
|
127
|
+
if jwt_token is None:
|
|
128
|
+
raise ValueError("A login access JWT is required")
|
|
129
|
+
if not isinstance(label, str) or not label:
|
|
130
|
+
raise ValueError("label is required")
|
|
131
|
+
return self._request("DELETE", "/user/del_keys", body={"label": label}, jwt_token=jwt_token)
|
|
132
|
+
|
|
133
|
+
def close(self):
|
|
134
|
+
self._session.close()
|
|
135
|
+
|
|
136
|
+
def __enter__(self):
|
|
137
|
+
return self
|
|
138
|
+
|
|
139
|
+
def __exit__(self, *args):
|
|
140
|
+
self.close()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
MaterialsAPI = PDFData_API
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdfdata-api
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python client for the PDFData materials database API
|
|
5
|
+
Author-email: PDF Database Team <contact@pdfdata.org>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://pdfdata.org
|
|
8
|
+
Project-URL: Documentation, https://pdfdata.org/documents/api
|
|
9
|
+
Project-URL: Source, https://github.com/yanglonggroup/pdfDBflask
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE.txt
|
|
13
|
+
Requires-Dist: requests>=2.25.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# PDFData Python client
|
|
17
|
+
|
|
18
|
+
Standalone client for `https://pdfdata.org/api/v1`. Requires Python 3.9+ and
|
|
19
|
+
`requests`; Flask, MongoDB and scientific packages are not client dependencies.
|
|
20
|
+
Version 0.2.0 source and build configuration are in this repository. A public
|
|
21
|
+
PyPI release has not been made as part of this change.
|
|
22
|
+
|
|
23
|
+
Install from a local checkout (repository root):
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
python -m pip install ./src/pdfdb_backend
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or install the built wheel supplied with a release:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
python -m pip install /path/to/pdfdata_api-0.2.0-py3-none-any.whl
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Generate a key on the website's API page after signing in. Set it in an
|
|
36
|
+
environment variable and query:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import os
|
|
40
|
+
from pdfdata_api import PDFData_API
|
|
41
|
+
|
|
42
|
+
with PDFData_API(api_key=os.environ["PDFDATA_API_KEY"]) as client:
|
|
43
|
+
page = client.get_materials(elements="Si,O", per_page=20)
|
|
44
|
+
material = client.get_material("mp-10009-X")
|
|
45
|
+
curve = client.get_pdf_data("mp-10009-X")
|
|
46
|
+
all_matches = client.get_all_materials(elements="Si,O")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`get_materials()` and `search()` return one page by default. Page size is 1–100.
|
|
50
|
+
`get_all_materials()` and `search_all()` collect successive pages. Legacy client
|
|
51
|
+
calls with `per_page=0` also collect successive pages; direct HTTP requests must
|
|
52
|
+
use page sizes 1–100. Collection is not a database snapshot while data changes.
|
|
53
|
+
|
|
54
|
+
Advanced search:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
result = client.search({
|
|
58
|
+
"elements": {"all": ["Si"], "none": ["Au"]},
|
|
59
|
+
"qmax": "[10,30]",
|
|
60
|
+
"page": 1,
|
|
61
|
+
"per_page": 20,
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For applications already holding a website **access JWT**, `PDFData_API()` can
|
|
66
|
+
call `generate_api_key(jwt_token)`, `get_api_keys(jwt_token)` and
|
|
67
|
+
`delete_api_key(jwt_token, "Key 1")`. The generated key is set on the client.
|
|
68
|
+
Key management requires the login JWT; material queries require the API key.
|
|
69
|
+
`generate_api_key` creates a new key on each call and is not automatically retried.
|
|
70
|
+
|
|
71
|
+
`MaterialsAPI` remains an alias of `PDFData_API`. The old import
|
|
72
|
+
`from PDFData_API import PDFData_API` remains supported. Backend source imports
|
|
73
|
+
`from app.api.client import MaterialsAPI` forward to the same implementation.
|
|
74
|
+
The default timeout is 30 seconds and can be set with `timeout=60`. HTTP errors
|
|
75
|
+
raise `requests.HTTPError`; inspect `exc.response.status_code` and JSON `code`.
|
|
76
|
+
|
|
77
|
+
Build from this directory:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
python -m build
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Only `pdfdata_api` and the legacy `PDFData_API` module are included in the
|
|
84
|
+
distribution. Production environment files and backend code are excluded.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
PDFData_API.py
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
pdfdata_api/__init__.py
|
|
7
|
+
pdfdata_api/client.py
|
|
8
|
+
pdfdata_api.egg-info/PKG-INFO
|
|
9
|
+
pdfdata_api.egg-info/SOURCES.txt
|
|
10
|
+
pdfdata_api.egg-info/dependency_links.txt
|
|
11
|
+
pdfdata_api.egg-info/requires.txt
|
|
12
|
+
pdfdata_api.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.25.0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pdfdata-api"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Python client for the PDFData materials database API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
authors = [{name = "PDF Database Team", email = "contact@pdfdata.org"}]
|
|
12
|
+
dependencies = ["requests>=2.25.0"]
|
|
13
|
+
license = "BSD-3-Clause"
|
|
14
|
+
license-files = ["LICENSE.txt"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://pdfdata.org"
|
|
18
|
+
Documentation = "https://pdfdata.org/documents/api"
|
|
19
|
+
Source = "https://github.com/yanglonggroup/pdfDBflask"
|
|
20
|
+
|
|
21
|
+
[tool.setuptools]
|
|
22
|
+
packages = ["pdfdata_api"]
|
|
23
|
+
py-modules = ["PDFData_API"]
|