pyalex 0.15.1__py3-none-any.whl → 0.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyalex/_version.py +9 -4
- pyalex/api.py +85 -14
- {pyalex-0.15.1.dist-info → pyalex-0.16.dist-info}/METADATA +20 -9
- pyalex-0.16.dist-info/RECORD +8 -0
- {pyalex-0.15.1.dist-info → pyalex-0.16.dist-info}/WHEEL +1 -1
- pyalex-0.15.1.dist-info/RECORD +0 -8
- {pyalex-0.15.1.dist-info → pyalex-0.16.dist-info}/LICENSE +0 -0
- {pyalex-0.15.1.dist-info → pyalex-0.16.dist-info}/top_level.txt +0 -0
pyalex/_version.py
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
# file generated by
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
3
6
|
TYPE_CHECKING = False
|
|
4
7
|
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
6
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
12
|
else:
|
|
8
13
|
VERSION_TUPLE = object
|
|
@@ -12,5 +17,5 @@ __version__: str
|
|
|
12
17
|
__version_tuple__: VERSION_TUPLE
|
|
13
18
|
version_tuple: VERSION_TUPLE
|
|
14
19
|
|
|
15
|
-
__version__ = version = '0.
|
|
16
|
-
__version_tuple__ = version_tuple = (0,
|
|
20
|
+
__version__ = version = '0.16'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 16)
|
pyalex/api.py
CHANGED
|
@@ -31,6 +31,32 @@ config = AlexConfig(
|
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
class or_(dict):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class _LogicalExpression:
|
|
39
|
+
token = None
|
|
40
|
+
|
|
41
|
+
def __init__(self, value):
|
|
42
|
+
self.value = value
|
|
43
|
+
|
|
44
|
+
def __str__(self) -> str:
|
|
45
|
+
return f"{self.token}{self.value}"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class not_(_LogicalExpression):
|
|
49
|
+
token = "!"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class gt_(_LogicalExpression):
|
|
53
|
+
token = ">"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class lt_(_LogicalExpression):
|
|
57
|
+
token = "<"
|
|
58
|
+
|
|
59
|
+
|
|
34
60
|
def _quote_oa_value(v):
|
|
35
61
|
"""Prepare a value for the OpenAlex API.
|
|
36
62
|
|
|
@@ -41,30 +67,40 @@ def _quote_oa_value(v):
|
|
|
41
67
|
if isinstance(v, bool):
|
|
42
68
|
return str(v).lower()
|
|
43
69
|
|
|
70
|
+
if isinstance(v, _LogicalExpression) and isinstance(v.value, str):
|
|
71
|
+
v.value = quote_plus(v.value)
|
|
72
|
+
return v
|
|
73
|
+
|
|
44
74
|
if isinstance(v, str):
|
|
45
75
|
return quote_plus(v)
|
|
46
76
|
|
|
47
77
|
return v
|
|
48
78
|
|
|
49
79
|
|
|
50
|
-
def _flatten_kv(d, prefix=""):
|
|
80
|
+
def _flatten_kv(d, prefix=None, logical="+"):
|
|
81
|
+
if prefix is None and not isinstance(d, dict):
|
|
82
|
+
raise ValueError("prefix should be set if d is not a dict")
|
|
83
|
+
|
|
51
84
|
if isinstance(d, dict):
|
|
85
|
+
logical_subd = "|" if isinstance(d, or_) else logical
|
|
86
|
+
|
|
52
87
|
t = []
|
|
53
88
|
for k, v in d.items():
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
x = _flatten_kv(v, prefix=new_prefix)
|
|
59
|
-
t.append(x)
|
|
89
|
+
x = _flatten_kv(
|
|
90
|
+
v, prefix=f"{prefix}.{k}" if prefix else f"{k}", logical=logical_subd
|
|
91
|
+
)
|
|
92
|
+
t.append(x)
|
|
60
93
|
|
|
61
94
|
return ",".join(t)
|
|
95
|
+
elif isinstance(d, list):
|
|
96
|
+
list_str = logical.join([f"{_quote_oa_value(i)}" for i in d])
|
|
97
|
+
return f"{prefix}:{list_str}"
|
|
62
98
|
else:
|
|
63
99
|
return f"{prefix}:{_quote_oa_value(d)}"
|
|
64
100
|
|
|
65
101
|
|
|
66
102
|
def _params_merge(params, add_params):
|
|
67
|
-
for k
|
|
103
|
+
for k in add_params.keys():
|
|
68
104
|
if (
|
|
69
105
|
k in params
|
|
70
106
|
and isinstance(params[k], dict)
|
|
@@ -113,6 +149,18 @@ def invert_abstract(inv_index):
|
|
|
113
149
|
return " ".join(map(lambda x: x[0], sorted(l_inv, key=lambda x: x[1])))
|
|
114
150
|
|
|
115
151
|
|
|
152
|
+
def _wrap_values_nested_dict(d, func):
|
|
153
|
+
for k, v in d.items():
|
|
154
|
+
if isinstance(v, dict):
|
|
155
|
+
d[k] = _wrap_values_nested_dict(v, func)
|
|
156
|
+
elif isinstance(v, list):
|
|
157
|
+
d[k] = [func(i) for i in v]
|
|
158
|
+
else:
|
|
159
|
+
d[k] = func(v)
|
|
160
|
+
|
|
161
|
+
return d
|
|
162
|
+
|
|
163
|
+
|
|
116
164
|
class QueryError(ValueError):
|
|
117
165
|
pass
|
|
118
166
|
|
|
@@ -207,9 +255,6 @@ class BaseOpenAlex:
|
|
|
207
255
|
def __init__(self, params=None):
|
|
208
256
|
self.params = params
|
|
209
257
|
|
|
210
|
-
def _get_multi_items(self, record_list):
|
|
211
|
-
return self.filter(openalex_id="|".join(record_list)).get()
|
|
212
|
-
|
|
213
258
|
def _full_collection_name(self):
|
|
214
259
|
if self.params is not None and "q" in self.params.keys():
|
|
215
260
|
return (
|
|
@@ -234,10 +279,14 @@ class BaseOpenAlex:
|
|
|
234
279
|
|
|
235
280
|
def __getitem__(self, record_id):
|
|
236
281
|
if isinstance(record_id, list):
|
|
237
|
-
|
|
282
|
+
if len(record_id) > 100:
|
|
283
|
+
raise ValueError("OpenAlex does not support more than 100 ids")
|
|
284
|
+
|
|
285
|
+
return self.filter_or(openalex_id=record_id).get(per_page=len(record_id))
|
|
238
286
|
|
|
239
287
|
return self._get_from_url(
|
|
240
|
-
f"{self._full_collection_name()}/{record_id}",
|
|
288
|
+
f"{self._full_collection_name()}/{_quote_oa_value(record_id)}",
|
|
289
|
+
return_meta=False,
|
|
241
290
|
)
|
|
242
291
|
|
|
243
292
|
@property
|
|
@@ -322,7 +371,10 @@ class BaseOpenAlex:
|
|
|
322
371
|
def random(self):
|
|
323
372
|
return self.__getitem__("random")
|
|
324
373
|
|
|
325
|
-
def _add_params(self, argument, new_params):
|
|
374
|
+
def _add_params(self, argument, new_params, raise_if_exists=False):
|
|
375
|
+
if raise_if_exists:
|
|
376
|
+
raise NotImplementedError("raise_if_exists is not implemented")
|
|
377
|
+
|
|
326
378
|
if self.params is None:
|
|
327
379
|
self.params = {argument: new_params}
|
|
328
380
|
elif argument in self.params and isinstance(self.params[argument], dict):
|
|
@@ -336,6 +388,25 @@ class BaseOpenAlex:
|
|
|
336
388
|
self._add_params("filter", kwargs)
|
|
337
389
|
return self
|
|
338
390
|
|
|
391
|
+
def filter_and(self, **kwargs):
|
|
392
|
+
return self.filter(**kwargs)
|
|
393
|
+
|
|
394
|
+
def filter_or(self, **kwargs):
|
|
395
|
+
self._add_params("filter", or_(kwargs), raise_if_exists=False)
|
|
396
|
+
return self
|
|
397
|
+
|
|
398
|
+
def filter_not(self, **kwargs):
|
|
399
|
+
self._add_params("filter", _wrap_values_nested_dict(kwargs, not_))
|
|
400
|
+
return self
|
|
401
|
+
|
|
402
|
+
def filter_gt(self, **kwargs):
|
|
403
|
+
self._add_params("filter", _wrap_values_nested_dict(kwargs, gt_))
|
|
404
|
+
return self
|
|
405
|
+
|
|
406
|
+
def filter_lt(self, **kwargs):
|
|
407
|
+
self._add_params("filter", _wrap_values_nested_dict(kwargs, lt_))
|
|
408
|
+
return self
|
|
409
|
+
|
|
339
410
|
def search_filter(self, **kwargs):
|
|
340
411
|
self._add_params("filter", {f"{k}.search": v for k, v in kwargs.items()})
|
|
341
412
|
return self
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: pyalex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16
|
|
4
4
|
Summary: Python interface to the OpenAlex database
|
|
5
5
|
Author-email: Jonathan de Bruin <jonathandebruinos@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -17,10 +17,10 @@ License-File: LICENSE
|
|
|
17
17
|
Requires-Dist: requests
|
|
18
18
|
Requires-Dist: urllib3
|
|
19
19
|
Provides-Extra: lint
|
|
20
|
-
Requires-Dist: ruff
|
|
20
|
+
Requires-Dist: ruff; extra == "lint"
|
|
21
21
|
Provides-Extra: test
|
|
22
|
-
Requires-Dist: pytest
|
|
23
|
-
Requires-Dist: pytest-xdist
|
|
22
|
+
Requires-Dist: pytest; extra == "test"
|
|
23
|
+
Requires-Dist: pytest-xdist; extra == "test"
|
|
24
24
|
|
|
25
25
|
<p align="center">
|
|
26
26
|
<img alt="PyAlex - a Python wrapper for OpenAlex" src="https://github.com/J535D165/pyalex/raw/main/pyalex_repocard.svg">
|
|
@@ -126,7 +126,7 @@ Works()["W2741809807"]["open_access"]
|
|
|
126
126
|
The previous works also for Authors, Sources, Institutions, Concepts and Topics
|
|
127
127
|
|
|
128
128
|
```python
|
|
129
|
-
Authors()["
|
|
129
|
+
Authors()["A5027479191"]
|
|
130
130
|
Authors()["https://orcid.org/0000-0002-4297-0502"] # same
|
|
131
131
|
```
|
|
132
132
|
|
|
@@ -139,7 +139,6 @@ Works().random()
|
|
|
139
139
|
Authors().random()
|
|
140
140
|
Sources().random()
|
|
141
141
|
Institutions().random()
|
|
142
|
-
Concepts().random()
|
|
143
142
|
Topics().random()
|
|
144
143
|
Publishers().random()
|
|
145
144
|
Funders().random()
|
|
@@ -383,6 +382,10 @@ Works()["W2023271753"].ngrams()
|
|
|
383
382
|
All results from PyAlex can be serialized. For example, save the results to a JSON file:
|
|
384
383
|
|
|
385
384
|
```python
|
|
385
|
+
import json
|
|
386
|
+
from pathlib import Path
|
|
387
|
+
from pyalex import Work
|
|
388
|
+
|
|
386
389
|
with open(Path("works.json"), "w") as f:
|
|
387
390
|
json.dump(Works().get(), f)
|
|
388
391
|
|
|
@@ -394,7 +397,7 @@ with open(Path("works.json")) as f:
|
|
|
394
397
|
|
|
395
398
|
A list of awesome use cases of the OpenAlex dataset.
|
|
396
399
|
|
|
397
|
-
### Cited publications (referenced
|
|
400
|
+
### Cited publications (works referenced by this paper, outgoing citations)
|
|
398
401
|
|
|
399
402
|
```python
|
|
400
403
|
from pyalex import Works
|
|
@@ -405,6 +408,13 @@ w = Works()["W2741809807"]
|
|
|
405
408
|
Works()[w["referenced_works"]]
|
|
406
409
|
```
|
|
407
410
|
|
|
411
|
+
### Citing publications (other works that reference this paper, incoming citations)
|
|
412
|
+
|
|
413
|
+
```python
|
|
414
|
+
from pyalex import Works
|
|
415
|
+
Works().filter(cites="W2741809807").get()
|
|
416
|
+
```
|
|
417
|
+
|
|
408
418
|
### Get works of a single author
|
|
409
419
|
|
|
410
420
|
```python
|
|
@@ -463,6 +473,7 @@ R users can use the excellent [OpenAlexR](https://github.com/ropensci/openalexR)
|
|
|
463
473
|
|
|
464
474
|
> This library is a community contribution. The authors of this Python library aren't affiliated with OpenAlex.
|
|
465
475
|
|
|
476
|
+
This library is maintained by [J535D165](https://github.com/J535D165) and [PeterLombaers](https://github.com/PeterLombaers).
|
|
466
477
|
Feel free to reach out with questions, remarks, and suggestions. The
|
|
467
|
-
[issue tracker](/issues) is a good starting point. You can also
|
|
478
|
+
[issue tracker](/issues) is a good starting point. You can also reach out via
|
|
468
479
|
[jonathandebruinos@gmail.com](mailto:jonathandebruinos@gmail.com).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pyalex/__init__.py,sha256=52XK8om6IVD1Yiq_HYOCR6PUY56sPRHutGM03NOrGMQ,1467
|
|
2
|
+
pyalex/_version.py,sha256=5zc7xTIiU-8qDWOhJyQ0RIy_saYu1BECCONIFoa0eLw,508
|
|
3
|
+
pyalex/api.py,sha256=YqVMwNEkg_LQdIVzOSXHe4bRhfNFg_YmCJqG1MoY23Y,14993
|
|
4
|
+
pyalex-0.16.dist-info/LICENSE,sha256=Mhf5MImRYP06a1EPVJCpkpTstOOEfGajN3T_Fz4izMg,1074
|
|
5
|
+
pyalex-0.16.dist-info/METADATA,sha256=7qIHsL5k8LL01z7Yc8_zpuJnGH3Av23THNz4g6QLZWI,14224
|
|
6
|
+
pyalex-0.16.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
|
|
7
|
+
pyalex-0.16.dist-info/top_level.txt,sha256=D0An8hWy9e0xPhTaT6K-yuJKVeVV3bYGxZ6Y-v2WXSU,7
|
|
8
|
+
pyalex-0.16.dist-info/RECORD,,
|
pyalex-0.15.1.dist-info/RECORD
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
pyalex/__init__.py,sha256=52XK8om6IVD1Yiq_HYOCR6PUY56sPRHutGM03NOrGMQ,1467
|
|
2
|
-
pyalex/_version.py,sha256=po5_rvCFTU8xU9IC56wyK0-zfBgz_U4xX6CO2mv9Mzs,413
|
|
3
|
-
pyalex/api.py,sha256=JTOx0P037IOhhYVAigQO5uPsd1HMQC-SM3wny0_52uU,13236
|
|
4
|
-
pyalex-0.15.1.dist-info/LICENSE,sha256=Mhf5MImRYP06a1EPVJCpkpTstOOEfGajN3T_Fz4izMg,1074
|
|
5
|
-
pyalex-0.15.1.dist-info/METADATA,sha256=JSa8cKcjZUZ-lDo28WyuFN1GHEEWUHWLvSLaKh3IP10,13859
|
|
6
|
-
pyalex-0.15.1.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
|
7
|
-
pyalex-0.15.1.dist-info/top_level.txt,sha256=D0An8hWy9e0xPhTaT6K-yuJKVeVV3bYGxZ6Y-v2WXSU,7
|
|
8
|
-
pyalex-0.15.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|