pyzotero 1.6.15__py3-none-any.whl → 1.6.17__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.
pyzotero/zotero.py
CHANGED
|
@@ -43,10 +43,9 @@ from .filetransport import Client as File_Client
|
|
|
43
43
|
# Avoid hanging the application if there's no server response
|
|
44
44
|
timeout = 30
|
|
45
45
|
|
|
46
|
-
NOT_MODIFIED = 304
|
|
47
46
|
ONE_HOUR = 3600
|
|
48
47
|
DEFAULT_NUM_ITEMS = 50
|
|
49
|
-
|
|
48
|
+
DEFAULT_ITEM_LIMIT = 100
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
def build_url(base_url, path, args_dict=None):
|
|
@@ -450,8 +449,6 @@ class Zotero:
|
|
|
450
449
|
Returns a JSON document
|
|
451
450
|
"""
|
|
452
451
|
full_url = build_url(self.endpoint, request)
|
|
453
|
-
# The API doesn't return this any more, so we have to cheat
|
|
454
|
-
self.self_link = request
|
|
455
452
|
# ensure that we wait if there's an active backoff
|
|
456
453
|
self._check_backoff()
|
|
457
454
|
# don't set locale if the url already contains it
|
|
@@ -470,7 +467,7 @@ class Zotero:
|
|
|
470
467
|
params = {}
|
|
471
468
|
if not self.url_params:
|
|
472
469
|
self.url_params = {}
|
|
473
|
-
merged_params = {**
|
|
470
|
+
merged_params = {**self.url_params, **params}
|
|
474
471
|
# our incoming url might be from the "links" dict, in which case it will contain url parameters.
|
|
475
472
|
# Unfortunately, httpx doesn't like to merge query paramaters in the url string and passed params
|
|
476
473
|
# so we strip the url params, combining them with our existing url_params
|
|
@@ -484,6 +481,8 @@ class Zotero:
|
|
|
484
481
|
timeout=timeout,
|
|
485
482
|
)
|
|
486
483
|
self.request.encoding = "utf-8"
|
|
484
|
+
# The API doesn't return this any more, so we have to cheat
|
|
485
|
+
self.self_link = self.request.url
|
|
487
486
|
except httpx.UnsupportedProtocol:
|
|
488
487
|
# File URI handler logic
|
|
489
488
|
fc = File_Client()
|
|
@@ -517,15 +516,12 @@ class Zotero:
|
|
|
517
516
|
fragment = f"{parsed[2]}?{parsed[4]}"
|
|
518
517
|
extracted[key] = fragment
|
|
519
518
|
# add a 'self' link
|
|
520
|
-
parsed =
|
|
521
|
-
# strip 'format' query parameter
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
)
|
|
525
|
-
# rebuild url fragment
|
|
526
|
-
# this is a death march
|
|
519
|
+
parsed = urlparse(str(self.self_link))
|
|
520
|
+
# strip 'format' query parameter and rebuild query string
|
|
521
|
+
query_params = [(k, v) for k, v in parse_qsl(parsed.query) if k != "format"]
|
|
522
|
+
# rebuild url fragment with just path and query (consistent with other links)
|
|
527
523
|
extracted["self"] = urlunparse(
|
|
528
|
-
|
|
524
|
+
("", "", parsed.path, "", urlencode(query_params), "")
|
|
529
525
|
)
|
|
530
526
|
except KeyError:
|
|
531
527
|
# No links present, because it's a single item
|
|
@@ -571,7 +567,7 @@ class Zotero:
|
|
|
571
567
|
)
|
|
572
568
|
if backoff:
|
|
573
569
|
self._set_backoff(backoff)
|
|
574
|
-
return req.status_code == NOT_MODIFIED
|
|
570
|
+
return req.status_code == httpx.codes.NOT_MODIFIED
|
|
575
571
|
# Still plenty of life left in't
|
|
576
572
|
return False
|
|
577
573
|
|
|
@@ -580,7 +576,13 @@ class Zotero:
|
|
|
580
576
|
|
|
581
577
|
Also ensure that only valid format/content combinations are requested
|
|
582
578
|
"""
|
|
583
|
-
|
|
579
|
+
# Preserve constructor-level parameters (like locale) while allowing method-level overrides
|
|
580
|
+
if self.url_params is None:
|
|
581
|
+
self.url_params = {}
|
|
582
|
+
|
|
583
|
+
# Store existing params to preserve things like locale
|
|
584
|
+
preserved_params = self.url_params.copy()
|
|
585
|
+
|
|
584
586
|
# we want JSON by default
|
|
585
587
|
if not params.get("format"):
|
|
586
588
|
params["format"] = "json"
|
|
@@ -589,7 +591,7 @@ class Zotero:
|
|
|
589
591
|
params["format"] = "atom"
|
|
590
592
|
# TODO: rewrite format=atom, content=json request
|
|
591
593
|
if "limit" not in params or params.get("limit") == 0:
|
|
592
|
-
params["limit"] =
|
|
594
|
+
params["limit"] = DEFAULT_ITEM_LIMIT
|
|
593
595
|
# Need ability to request arbitrary number of results for version
|
|
594
596
|
# response
|
|
595
597
|
# -1 value is hack that works with current version
|
|
@@ -597,8 +599,10 @@ class Zotero:
|
|
|
597
599
|
del params["limit"]
|
|
598
600
|
# bib format can't have a limit
|
|
599
601
|
if params.get("format") == "bib":
|
|
600
|
-
|
|
601
|
-
|
|
602
|
+
params.pop("limit", None)
|
|
603
|
+
|
|
604
|
+
# Merge preserved params with new params (new params override existing ones)
|
|
605
|
+
self.url_params = {**preserved_params, **params}
|
|
602
606
|
|
|
603
607
|
def _build_query(self, query_string, no_params=False):
|
|
604
608
|
"""Set request parameters. Will always add the user ID if it hasn't
|
|
@@ -1638,7 +1642,7 @@ def error_handler(zot, req, exc=None):
|
|
|
1638
1642
|
|
|
1639
1643
|
if error_codes.get(req.status_code):
|
|
1640
1644
|
# check to see whether its 429
|
|
1641
|
-
if req.status_code == TOO_MANY_REQUESTS:
|
|
1645
|
+
if req.status_code == httpx.codes.TOO_MANY_REQUESTS:
|
|
1642
1646
|
# try to get backoff or delay duration
|
|
1643
1647
|
delay = req.headers.get("backoff") or req.headers.get("retry-after")
|
|
1644
1648
|
if not delay:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: pyzotero
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.17
|
|
4
4
|
Summary: Python wrapper for the Zotero API
|
|
5
5
|
Keywords: Zotero,DH
|
|
6
6
|
Author: Stephan Hügel
|
|
@@ -86,7 +86,7 @@ items = zot.top(limit=5)
|
|
|
86
86
|
# we've retrieved the latest five top-level items in our library
|
|
87
87
|
# we can print each item's item type and ID
|
|
88
88
|
for item in items:
|
|
89
|
-
print(
|
|
89
|
+
print(f"Item: {item['data']['itemType']} | Key: {item['data']['key']}")
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
# Documentation
|
|
@@ -95,8 +95,9 @@ Full documentation of available Pyzotero methods, code examples, and sample outp
|
|
|
95
95
|
|
|
96
96
|
# Installation
|
|
97
97
|
|
|
98
|
-
* Using [
|
|
99
|
-
* Using
|
|
98
|
+
* Using [uv][11]: `uv add pyzotero`
|
|
99
|
+
* Using [pip][10]: `pip install pyzotero`
|
|
100
|
+
* Using Anaconda:`conda install conda-forge::pyzotero`
|
|
100
101
|
* From a local clone, if you wish to install Pyzotero from a specific branch:
|
|
101
102
|
|
|
102
103
|
Example:
|
|
@@ -105,12 +106,13 @@ Example:
|
|
|
105
106
|
git clone git://github.com/urschrei/pyzotero.git
|
|
106
107
|
cd pyzotero
|
|
107
108
|
git checkout main
|
|
108
|
-
|
|
109
|
+
# specify --dev if you're planning on running tests
|
|
110
|
+
uv sync
|
|
109
111
|
```
|
|
110
112
|
|
|
111
113
|
## Testing
|
|
112
114
|
|
|
113
|
-
Run `pytest .` from the top-level directory.
|
|
115
|
+
Run `pytest .` from the top-level directory. This requires the `dev` dependency group to be installed: `uv sync --dev` / `pip install --group dev`
|
|
114
116
|
|
|
115
117
|
## Issues
|
|
116
118
|
|
|
@@ -118,14 +120,13 @@ The latest commits can be found on the [main branch][9], although new features a
|
|
|
118
120
|
|
|
119
121
|
## Pull Requests
|
|
120
122
|
|
|
121
|
-
Pull requests are welcomed. Please read the [contribution guidelines](CONTRIBUTING.md). In particular, please **base your PR on the `
|
|
123
|
+
Pull requests are welcomed. Please read the [contribution guidelines](CONTRIBUTING.md). In particular, please **base your PR on the `main` branch**.
|
|
122
124
|
|
|
123
125
|
## Versioning
|
|
124
126
|
|
|
125
127
|
As of v1.0.0, Pyzotero is versioned according to [Semver](http://semver.org); version increments are performed as follows:
|
|
126
128
|
|
|
127
129
|
|
|
128
|
-
|
|
129
130
|
1. MAJOR version will increment with incompatible API changes,
|
|
130
131
|
2. MINOR version will increment when functionality is added in a backwards-compatible manner, and
|
|
131
132
|
3. PATCH version will increment with backwards-compatible bug fixes.
|
|
@@ -149,5 +150,6 @@ Pyzotero is licensed under the [Blue Oak Model Licence 1.0.0][8]. See [LICENSE.m
|
|
|
149
150
|
[8]: https://opensource.org/license/blue-oak-model-license
|
|
150
151
|
[9]: https://github.com/urschrei/pyzotero/tree/main
|
|
151
152
|
[10]: http://www.pip-installer.org/en/latest/index.html
|
|
153
|
+
[11]: https://docs.astral.sh/uv
|
|
152
154
|
† This isn't strictly true: you only need an API key for personal libraries and non-public group libraries.
|
|
153
155
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
pyzotero/__init__.py,sha256=5QI4Jou9L-YJAf_oN9TgRXVKgt_Unc39oADo2Ch8bLI,243
|
|
2
|
+
pyzotero/filetransport.py,sha256=umLik1LLmrpgaNmyjvtBoqqcaMgIq79PYsTvN5vG-gY,5530
|
|
3
|
+
pyzotero/zotero.py,sha256=2Mjvr15sHRHR1MCeifniIXVtqqC4n-P_kDr8Z5Vdkhw,76427
|
|
4
|
+
pyzotero/zotero_errors.py,sha256=6obx9-pBO0z1bxt33vuzDluELvA5kSLCsfc-uGc3KNw,2660
|
|
5
|
+
pyzotero-1.6.17.dist-info/WHEEL,sha256=n2u5OFBbdZvCiUKAmfnY1Po2j3FB_NWfuUlt5WiAjrk,79
|
|
6
|
+
pyzotero-1.6.17.dist-info/METADATA,sha256=3h20funfN9wdaduCVZ8IBFFUB1K4IlH_Tlrj-OD7BmA,7292
|
|
7
|
+
pyzotero-1.6.17.dist-info/RECORD,,
|
pyzotero-1.6.15.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
pyzotero/__init__.py,sha256=5QI4Jou9L-YJAf_oN9TgRXVKgt_Unc39oADo2Ch8bLI,243
|
|
2
|
-
pyzotero/filetransport.py,sha256=umLik1LLmrpgaNmyjvtBoqqcaMgIq79PYsTvN5vG-gY,5530
|
|
3
|
-
pyzotero/zotero.py,sha256=u3ELdw3aC7qXOWmzKpMILxL1ZNwFIMTnPzA5xEnqTfE,76032
|
|
4
|
-
pyzotero/zotero_errors.py,sha256=6obx9-pBO0z1bxt33vuzDluELvA5kSLCsfc-uGc3KNw,2660
|
|
5
|
-
pyzotero-1.6.15.dist-info/WHEEL,sha256=pFCy50wRV2h7SjJ35YOsQUupaV45rMdgpNIvnXbG5bE,79
|
|
6
|
-
pyzotero-1.6.15.dist-info/METADATA,sha256=wVagjGr1flontsTU3oEhZ1eCWhTBqvyvFLQN3nj0A48,7176
|
|
7
|
-
pyzotero-1.6.15.dist-info/RECORD,,
|