pyzotero 1.7.4__tar.gz → 1.7.6__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.
- {pyzotero-1.7.4 → pyzotero-1.7.6}/PKG-INFO +1 -1
- {pyzotero-1.7.4 → pyzotero-1.7.6}/doc/conf.py +3 -1
- {pyzotero-1.7.4 → pyzotero-1.7.6}/doc/index.rst +121 -142
- {pyzotero-1.7.4 → pyzotero-1.7.6}/pyproject.toml +1 -1
- {pyzotero-1.7.4 → pyzotero-1.7.6}/src/pyzotero/zotero.py +10 -4
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/test_zotero.py +104 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/LICENSE.md +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/README.md +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/doc/Makefile +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/doc/_templates/layout.html +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/doc/cat.png +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/src/pyzotero/__init__.py +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/src/pyzotero/cli.py +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/src/pyzotero/filetransport.py +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/src/pyzotero/zotero_errors.py +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/__init__.py +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/attachments_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/citation_doc.xml +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/collection_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/collection_tags.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/collection_versions.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/collections_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/creation_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/groups_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/item_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/item_fields.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/item_file.pdf +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/item_template.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/item_types.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/item_versions.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/items_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/keys_doc.txt +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/api_responses/tags_doc.json +0 -0
- {pyzotero-1.7.4 → pyzotero-1.7.6}/tests/test_async.py +0 -0
|
@@ -117,7 +117,9 @@ RTD_NEW_THEME = True
|
|
|
117
117
|
# Theme options are theme-specific and customize the look and feel of a theme
|
|
118
118
|
# further. For a list of options available for each theme, see the
|
|
119
119
|
# documentation.
|
|
120
|
-
|
|
120
|
+
html_theme_options = {
|
|
121
|
+
"collapse_navigation": False,
|
|
122
|
+
}
|
|
121
123
|
|
|
122
124
|
# Add any paths that contain custom themes here, relative to this directory.
|
|
123
125
|
# html_theme_path = []
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
Description
|
|
2
|
-
===========
|
|
3
1
|
Pyzotero is a Python wrapper for the `Zotero API (v3) <https://www.zotero.org/support/dev/web_api/v3/start>`_.
|
|
4
2
|
|
|
5
3
|
|
|
@@ -12,6 +10,7 @@ Pyzotero is a Python wrapper for the `Zotero API (v3) <https://www.zotero.org/su
|
|
|
12
10
|
|
|
13
11
|
|
|
14
12
|
|
|
13
|
+
===============================
|
|
15
14
|
Getting started (short version)
|
|
16
15
|
===============================
|
|
17
16
|
1. ``uv add pyzotero`` or ``pip install pyzotero`` or ``conda install conda-forge::pyzotero``
|
|
@@ -42,21 +41,20 @@ Getting started (short version)
|
|
|
42
41
|
Refer to the :ref:`read` and :ref:`write`.
|
|
43
42
|
|
|
44
43
|
|
|
44
|
+
=============================================
|
|
45
45
|
Installation, testing, usage (longer version)
|
|
46
46
|
=============================================
|
|
47
47
|
|
|
48
|
-
============
|
|
49
48
|
Installation
|
|
50
|
-
|
|
49
|
+
------------
|
|
51
50
|
Using `uv <https://docs.astral.sh/uv/concepts/projects/dependencies/#adding-dependencies>`_: ``uv add pyzotero``
|
|
52
51
|
|
|
53
52
|
Using `pip <http://www.pip-installer.org/en/latest/index.html>`_: ``pip install pyzotero``
|
|
54
53
|
|
|
55
54
|
Using `Anaconda <https://www.anaconda.com/distribution/>`_: ``conda install conda-forge::pyzotero``
|
|
56
55
|
|
|
57
|
-
-------------------------------
|
|
58
56
|
Optional: Command-Line Interface
|
|
59
|
-
|
|
57
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
60
58
|
|
|
61
59
|
Pyzotero includes an optional command-line interface for searching and querying your local Zotero library.
|
|
62
60
|
|
|
@@ -86,29 +84,26 @@ The Pyzotero source tarball is also available from `PyPI <http://pypi.python.org
|
|
|
86
84
|
|
|
87
85
|
|
|
88
86
|
|
|
89
|
-
===============================
|
|
90
87
|
Installing development versions
|
|
91
|
-
|
|
88
|
+
-------------------------------
|
|
92
89
|
Pyzotero remains in development as of 2025. Unstable development versions can be found on the `Github main branch <https://github.com/urschrei/pyzotero/tree/main>`_, and installed directly from a checked-out ``main`` branch on a local clone, as in the example above: specify ``--dev`` (uv) / ``--group dev`` (pip).
|
|
93
90
|
|
|
94
91
|
|
|
95
|
-
=======
|
|
96
92
|
Testing
|
|
97
|
-
|
|
93
|
+
-------
|
|
98
94
|
Testing requires installation of the ``dev`` dependency group (see above).
|
|
99
95
|
|
|
100
96
|
Run ``pytest .`` from the top-level directory.
|
|
101
97
|
|
|
102
98
|
.. _cli-usage:
|
|
103
99
|
|
|
104
|
-
==========================
|
|
105
100
|
Command-Line Interface Usage
|
|
106
|
-
|
|
101
|
+
----------------------------
|
|
107
102
|
|
|
108
103
|
The Pyzotero CLI connects to your local Zotero installation and allows you to search your library, list collections, and view item types.
|
|
109
104
|
|
|
110
105
|
Basic Commands
|
|
111
|
-
|
|
106
|
+
~~~~~~~~~~~~~~
|
|
112
107
|
|
|
113
108
|
Search for top-level items:
|
|
114
109
|
|
|
@@ -153,14 +148,14 @@ List available item types:
|
|
|
153
148
|
pyzotero itemtypes
|
|
154
149
|
|
|
155
150
|
Search Behaviour
|
|
156
|
-
|
|
151
|
+
~~~~~~~~~~~~~~~~
|
|
157
152
|
|
|
158
153
|
By default, ``pyzotero search`` searches only top-level item titles and metadata fields.
|
|
159
154
|
|
|
160
155
|
When the ``--fulltext`` flag is used, the search expands to include all full-text indexed content, including PDFs and other attachments. Since most full-text content comes from PDF attachments rather than top-level items, the CLI automatically retrieves the parent bibliographic items for any matching attachments. This ensures you receive useful bibliographic records (journal articles, books, etc.) rather than raw attachment items.
|
|
161
156
|
|
|
162
157
|
Output Format
|
|
163
|
-
|
|
158
|
+
~~~~~~~~~~~~~
|
|
164
159
|
|
|
165
160
|
By default, the CLI outputs human-readable text with all relevant metadata including:
|
|
166
161
|
|
|
@@ -171,18 +166,16 @@ By default, the CLI outputs human-readable text with all relevant metadata inclu
|
|
|
171
166
|
Use the ``--json`` flag to output structured JSON suitable for consumption by other tools and agents.
|
|
172
167
|
|
|
173
168
|
|
|
174
|
-
======================
|
|
175
169
|
Building Documentation
|
|
176
|
-
|
|
170
|
+
----------------------
|
|
177
171
|
If you wish to build Pyzotero's documentation for offline use, it can be built from the ``doc`` directory of a local git repo by running ``make`` followed by the desired output format(s) (``html``, ``epub``, ``latexpdf`` etc.)
|
|
178
172
|
|
|
179
173
|
This functionality requires Sphinx.
|
|
180
174
|
See the `Sphinx documentation <http://sphinx.pocoo.org/tutorial.html#running-the-build>`_ for full details.
|
|
181
175
|
|
|
182
176
|
|
|
183
|
-
================
|
|
184
177
|
Reporting issues
|
|
185
|
-
|
|
178
|
+
----------------
|
|
186
179
|
If you encounter an error while using Pyzotero, please open an issue on its `Github issues page <https://github.com/urschrei/pyzotero/issues>`_.
|
|
187
180
|
|
|
188
181
|
|
|
@@ -222,10 +215,11 @@ Example:
|
|
|
222
215
|
.. _read:
|
|
223
216
|
|
|
224
217
|
Errors
|
|
225
|
-
|
|
218
|
+
------
|
|
226
219
|
Where possible, any ``ZoteroError`` which is raised will preserve the underlying error in its ``__cause__`` and ``__context__`` properties, should you wish to work with these directly.
|
|
227
220
|
|
|
228
221
|
|
|
222
|
+
====================
|
|
229
223
|
Read API Methods
|
|
230
224
|
====================
|
|
231
225
|
|
|
@@ -235,6 +229,90 @@ Read API Methods
|
|
|
235
229
|
.. tip::
|
|
236
230
|
The Read API returns 25 results by default (the API documentation claims 50). In the interests of usability, Pyzotero returns 100 items by default, by setting the API ``limit`` parameter to 100, unless it's set by the user. If you wish to retrieve e.g. all top-level items without specifying a ``limit`` parameter, you'll have to wrap your call with :py:meth:`Zotero.everything()`: ``results = zot.everything(zot.top())``.
|
|
237
231
|
|
|
232
|
+
Search / Request Parameters for Read API calls
|
|
233
|
+
----------------------------------------------
|
|
234
|
+
|
|
235
|
+
Additional parameters may be set on Read API methods **following any required parameters**, or set using the :py:meth:`Zotero.add_parameters()` method detailed below.
|
|
236
|
+
|
|
237
|
+
The following two examples produce the same result:
|
|
238
|
+
|
|
239
|
+
.. code-block:: python
|
|
240
|
+
|
|
241
|
+
# set parameters on the call itself
|
|
242
|
+
z = zot.top(limit=7, start=3)
|
|
243
|
+
|
|
244
|
+
# set parameters using explicit method
|
|
245
|
+
zot.add_parameters(limit=7, start=3)
|
|
246
|
+
z = zot.top()
|
|
247
|
+
|
|
248
|
+
The following parameters are **optional**.
|
|
249
|
+
|
|
250
|
+
**You may also set a search term here, using the 'itemType', 'q', 'qmode', or 'tag' parameters**.
|
|
251
|
+
|
|
252
|
+
This area of the Zotero Read API is under development, and may change frequently. See `the API documentation <https://www.zotero.org/support/dev/web_api/v3/basics#read_requests>`_ for the most up-to-date details of search syntax usage and export format details.
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
.. py:method:: Zotero.add_parameters([format=None, itemKey=None, itemType=None, q=None, qmode=None, since=None, tag=None, sort=None, direction=None, limit=None, start=None, [content=None[ ,style=None]]])
|
|
257
|
+
|
|
258
|
+
:param str format: "atom", "bib", "bibtex", json", "keys", "versions". Pyzotero retrieves and decodes JSON responses by default
|
|
259
|
+
|
|
260
|
+
.. attention::
|
|
261
|
+
|
|
262
|
+
Setting ``format='bib'`` will remove the ``limit`` parameter if it's been set, as **the API does not allow a limit on bibliography output**; it instead enforces a limit of 150 items, and if the set of items you are trying to generate a bibliography for exceeds 150, an error will be raised.
|
|
263
|
+
|
|
264
|
+
:param str itemKey: A comma-separated list of item keys. Valid only for item requests. Up to 50 items can be specified in a single request
|
|
265
|
+
|
|
266
|
+
Search parameters:
|
|
267
|
+
|
|
268
|
+
:param str itemType: item type search. See the `Search Syntax <https://www.zotero.org/support/dev/web_api/v3/basics#search_syntax>`_ for details
|
|
269
|
+
:param str q: Quick search. Searches titles and individual creator fields by default. Use the ``qmode`` parameter to change the mode. Currently supports phrase searching only
|
|
270
|
+
:param str qmode: Quick search mode. To include full-text content in the search, use ``everything``. Defaults to ``titleCreatorYear``. Searching of other fields will be possible in the future
|
|
271
|
+
:param int since: default ``0``. Return only objects modified after the specified library version
|
|
272
|
+
:param str tag: tag search. See the `Search Syntax <https://www.zotero.org/support/dev/web_api/v3/basics#search_syntax>`_ for details. More than one tag may be passed by passing a list of strings – These are treated as ``AND`` search terms, meaning only items which include all of the specified tags are returned. You can search for items matching any tag in a list by using ``OR``: ``"tag1 OR tag2"``, and all items which exclude a tag: ``"-tag"``.
|
|
273
|
+
|
|
274
|
+
The following parameters can be used for search requests:
|
|
275
|
+
|
|
276
|
+
:param str sort: The name of the field by which entries are sorted: (``dateAdded``, ``dateModified``, ``title``, ``creator``, ``type``, ``date``, ``publisher``, ``publicationTitle``, ``journalAbbreviation``, ``language``, ``accessDate``, ``libraryCatalog``, ``callNumber``, ``rights``, ``addedBy``, ``numItems``, ``tags``)
|
|
277
|
+
:param str direction: ``asc`` or ``desc``
|
|
278
|
+
:param int limit: 1 – 100 or None
|
|
279
|
+
:param int start: 1 – total number of items in your library or None
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
If you wish to retrieve citation or bibliography entries, use the following parameters:
|
|
283
|
+
|
|
284
|
+
:param str content: 'bib', 'html', or one of the export formats (see below). If 'bib' is passed, you may **also** pass:
|
|
285
|
+
:param str style: Any valid CSL style in the Zotero style repository
|
|
286
|
+
:param str linkwrap: Set this to "1" to have URLs in bibliography entries (see below) wrapped in ``<a>`` tags.
|
|
287
|
+
:rtype: list of HTML strings or None.
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
.. note::
|
|
291
|
+
|
|
292
|
+
Any parameters you set will be valid **for the next call only**. Any parameters set using ``add_parameters()`` will be overridden by parameters you pass in the call itself.
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
A note on the ``content`` and ``style`` parameters:
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
|
|
299
|
+
.. code-block:: python
|
|
300
|
+
|
|
301
|
+
zot.add_parameters(content='bib', style='mla')
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
If these are set, the return value is a list of UTF-8 formatted HTML ``div`` elements, each containing an item:
|
|
305
|
+
|
|
306
|
+
``['<div class="csl-entry">(content)</div>']``.
|
|
307
|
+
|
|
308
|
+
You may also set ``content='citation'`` if you wish to retrieve citations. Similar to ``bib``, the result will be a list of one or more HTML ``span`` elements.
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
If you select one of the available `export formats <https://www.zotero.org/support/dev/web_api/v3/basics#export_formats>`_ as the ``content`` parameter, pyzotero will in most cases return a list of unicode strings in the format you specified. The exception is the ``csljson`` format, which is parsed into a list of dicts. Please note that you must provide a ``limit`` parameter if you specify one of these export formats. Multiple simultaneous retrieval of particular formats, e.g. ``content="json,coins"`` is not currently supported.
|
|
312
|
+
|
|
313
|
+
If you set ``format='keys'``, a newline-delimited string containing item keys will be returned
|
|
314
|
+
|
|
315
|
+
If you set ``format='bibtex'``, a `bibtexparser <https://bibtexparser.readthedocs.io/en/v0.6.2/bibtexparser.html#bibdatabase.BibDatabase.entries>`_ object containing citations will be returned. You can access the citations as a list of dicts using the ``.entries`` property. The bibtexparser object also implements a `dump method <https://bibtexparser.readthedocs.io/en/v0.6.2/bibtexparser.html#bibtexparser.dump>`_, if you'd like to write your citations to a ``.bib`` file.
|
|
238
316
|
|
|
239
317
|
.. py:method:: Zotero.key_info()
|
|
240
318
|
|
|
@@ -242,9 +320,8 @@ Read API Methods
|
|
|
242
320
|
|
|
243
321
|
:rtype: dict
|
|
244
322
|
|
|
245
|
-
====================
|
|
246
323
|
Retrieving Items
|
|
247
|
-
|
|
324
|
+
----------------
|
|
248
325
|
|
|
249
326
|
.. tip::
|
|
250
327
|
In contrast to the v1 API, a great deal of additional metadata is now returned. In most cases, simply accessing items by referring to their ``item['data']`` key will suffice.
|
|
@@ -400,9 +477,8 @@ Example of returned item data:
|
|
|
400
477
|
|
|
401
478
|
See :ref:`'Hello World' <hello-world>` example, above
|
|
402
479
|
|
|
403
|
-
====================
|
|
404
480
|
Retrieving Files
|
|
405
|
-
|
|
481
|
+
----------------
|
|
406
482
|
|
|
407
483
|
.. py:method:: Zotero.file(itemID[, search/request parameters])
|
|
408
484
|
|
|
@@ -440,9 +516,8 @@ Retrieving Files
|
|
|
440
516
|
|
|
441
517
|
File retrieval and dumping should work for most common document, audio and video file formats. If you encounter an error, `please open an issue <https://github.com/urschrei/pyzotero/issues>`_.
|
|
442
518
|
|
|
443
|
-
=======================
|
|
444
519
|
Retrieving Collections
|
|
445
|
-
|
|
520
|
+
----------------------
|
|
446
521
|
.. py:method:: Zotero.collections([search/request parameters])
|
|
447
522
|
|
|
448
523
|
Returns a library's collections. **This includes subcollections**.
|
|
@@ -499,9 +574,8 @@ Example of returned collection data:
|
|
|
499
574
|
u'version': 778}]
|
|
500
575
|
|
|
501
576
|
|
|
502
|
-
==========================
|
|
503
577
|
Retrieving groups
|
|
504
|
-
|
|
578
|
+
-----------------
|
|
505
579
|
.. py:method:: Zotero.groups([search/request parameters])
|
|
506
580
|
|
|
507
581
|
Retrieve the Zotero group data to which the current library_id and api_key has access
|
|
@@ -535,9 +609,8 @@ Example of returned group data:
|
|
|
535
609
|
u'version': 0}]
|
|
536
610
|
|
|
537
611
|
|
|
538
|
-
===================
|
|
539
612
|
Retrieving Tags
|
|
540
|
-
|
|
613
|
+
---------------
|
|
541
614
|
|
|
542
615
|
.. py:method:: Zotero.tags([search/request parameters])
|
|
543
616
|
|
|
@@ -558,9 +631,8 @@ Example of returned tag data:
|
|
|
558
631
|
|
|
559
632
|
['Authority in literature', 'Errata']
|
|
560
633
|
|
|
561
|
-
==============================
|
|
562
634
|
Retrieving Version Information
|
|
563
|
-
|
|
635
|
+
------------------------------
|
|
564
636
|
|
|
565
637
|
The `Zotero API <https://www.zotero.org/support/dev/web_api/v3/syncing>`_ recommends requesting version information for all (or all changed) items and collections when implementing syncing. The following convenience methods (which by default return an unlimited number of responses) simplify this process.
|
|
566
638
|
|
|
@@ -585,9 +657,8 @@ Example of returned version data:
|
|
|
585
657
|
{'C9KW275P': 3915, 'IB489TKM': 4025 }
|
|
586
658
|
|
|
587
659
|
|
|
588
|
-
=================
|
|
589
660
|
Full–Text Content
|
|
590
|
-
|
|
661
|
+
-----------------
|
|
591
662
|
|
|
592
663
|
These methods allow the retrieval of full–text content for given library items
|
|
593
664
|
|
|
@@ -649,9 +720,8 @@ Example payload:
|
|
|
649
720
|
"totalPages": 50
|
|
650
721
|
}
|
|
651
722
|
|
|
652
|
-
==============================================
|
|
653
723
|
The ``follow()``, and ``everything()`` methods
|
|
654
|
-
|
|
724
|
+
----------------------------------------------
|
|
655
725
|
|
|
656
726
|
These methods (currently experimental) aim to make Pyzotero a little more RESTful. Following any Read API call which can retrieve **multiple items**, calling ``follow()`` will repeat that call, but for the next *x* number of items, where *x* is either a number set by the user for the original call, or 50 by default. Each subsequent call to ``follow()`` will extend the offset.
|
|
657
727
|
|
|
@@ -685,7 +755,7 @@ Example:
|
|
|
685
755
|
The ``everything()`` method should work with all Pyzotero Read API calls which can return multiple items, but has not yet been extensively tested. `Feedback is welcomed <https://github.com/urschrei/pyzotero/issues>`_.
|
|
686
756
|
|
|
687
757
|
Related generator methods
|
|
688
|
-
|
|
758
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
689
759
|
|
|
690
760
|
The :py:meth:`Zotero.iterfollow()` and :py:meth:`Zotero.makeiter()` methods are available for users who prefer to work directly with generators:
|
|
691
761
|
|
|
@@ -721,9 +791,8 @@ Example:
|
|
|
721
791
|
|
|
722
792
|
.. warning:: The ``follow()``, ``everything()`` and ``makeiter()`` methods are only valid for methods which can return multiple library items. For instance, you cannot use ``follow()`` after an ``item()`` call. The generator methods will raise a ``StopIteration`` error when all available items retrievable by your chosen API call have been exhausted.
|
|
723
793
|
|
|
724
|
-
======================
|
|
725
794
|
Retrieving item counts
|
|
726
|
-
|
|
795
|
+
----------------------
|
|
727
796
|
|
|
728
797
|
If you wish to retrieve item counts for subsets of a library, you can use the following methods:
|
|
729
798
|
|
|
@@ -739,9 +808,8 @@ If you wish to retrieve item counts for subsets of a library, you can use the fo
|
|
|
739
808
|
|
|
740
809
|
:rtype: int
|
|
741
810
|
|
|
742
|
-
================================
|
|
743
811
|
Retrieving last modified version
|
|
744
|
-
|
|
812
|
+
--------------------------------
|
|
745
813
|
|
|
746
814
|
If you wish to retrieve the last modified version of a user or group library, you can use the following method:
|
|
747
815
|
|
|
@@ -751,103 +819,14 @@ If you wish to retrieve the last modified version of a user or group library, yo
|
|
|
751
819
|
|
|
752
820
|
:rtype: int
|
|
753
821
|
|
|
754
|
-
|
|
755
|
-
==============================================
|
|
756
|
-
Search / Request Parameters for Read API calls
|
|
757
|
-
==============================================
|
|
758
|
-
|
|
759
|
-
Additional parameters may be set on Read API methods **following any required parameters**, or set using the :py:meth:`Zotero.add_parameters()` method detailed below.
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
The following two examples produce the same result:
|
|
763
|
-
|
|
764
|
-
.. code-block:: python
|
|
765
|
-
|
|
766
|
-
# set parameters on the call itself
|
|
767
|
-
z = zot.top(limit=7, start=3)
|
|
768
|
-
|
|
769
|
-
# set parameters using explicit method
|
|
770
|
-
zot.add_parameters(limit=7, start=3)
|
|
771
|
-
z = zot.top()
|
|
772
|
-
|
|
773
|
-
The following parameters are **optional**.
|
|
774
|
-
|
|
775
|
-
**You may also set a search term here, using the 'itemType', 'q', 'qmode', or 'tag' parameters**.
|
|
776
|
-
|
|
777
|
-
This area of the Zotero Read API is under development, and may change frequently. See `the API documentation <https://www.zotero.org/support/dev/web_api/v3/basics#read_requests>`_ for the most up-to-date details of search syntax usage and export format details.
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
.. py:method:: Zotero.add_parameters([format=None, itemKey=None, itemType=None, q=None, qmode=None, since=None, tag=None, sort=None, direction=None, limit=None, start=None, [content=None[ ,style=None]]])
|
|
782
|
-
|
|
783
|
-
:param str format: "atom", "bib", "bibtex", json", "keys", "versions". Pyzotero retrieves and decodes JSON responses by default
|
|
784
|
-
|
|
785
|
-
.. attention::
|
|
786
|
-
|
|
787
|
-
Setting ``format='bib'`` will remove the ``limit`` parameter if it's been set, as **the API does not allow a limit on bibliography output**; it instead enforces a limit of 150 items, and if the set of items you are trying to generate a bibliography for exceeds 150, an error will be raised.
|
|
788
|
-
|
|
789
|
-
:param str itemKey: A comma-separated list of item keys. Valid only for item requests. Up to 50 items can be specified in a single request
|
|
790
|
-
|
|
791
|
-
Search parameters:
|
|
792
|
-
|
|
793
|
-
:param str itemType: item type search. See the `Search Syntax <https://www.zotero.org/support/dev/web_api/v3/basics#search_syntax>`_ for details
|
|
794
|
-
:param str q: Quick search. Searches titles and individual creator fields by default. Use the ``qmode`` parameter to change the mode. Currently supports phrase searching only
|
|
795
|
-
:param str qmode: Quick search mode. To include full-text content in the search, use ``everything``. Defaults to ``titleCreatorYear``. Searching of other fields will be possible in the future
|
|
796
|
-
:param int since: default ``0``. Return only objects modified after the specified library version
|
|
797
|
-
:param str tag: tag search. See the `Search Syntax <https://www.zotero.org/support/dev/web_api/v3/basics#search_syntax>`_ for details. More than one tag may be passed by passing a list of strings – These are treated as ``AND`` search terms, meaning only items which include all of the specified tags are returned. You can search for items matching any tag in a list by using ``OR``: ``"tag1 OR tag2"``, and all items which exclude a tag: ``"-tag"``.
|
|
798
|
-
|
|
799
|
-
The following parameters can be used for search requests:
|
|
800
|
-
|
|
801
|
-
:param str sort: The name of the field by which entries are sorted: (``dateAdded``, ``dateModified``, ``title``, ``creator``, ``type``, ``date``, ``publisher``, ``publicationTitle``, ``journalAbbreviation``, ``language``, ``accessDate``, ``libraryCatalog``, ``callNumber``, ``rights``, ``addedBy``, ``numItems``, ``tags``)
|
|
802
|
-
:param str direction: ``asc`` or ``desc``
|
|
803
|
-
:param int limit: 1 – 100 or None
|
|
804
|
-
:param int start: 1 – total number of items in your library or None
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
If you wish to retrieve citation or bibliography entries, use the following parameters:
|
|
808
|
-
|
|
809
|
-
:param str content: 'bib', 'html', or one of the export formats (see below). If 'bib' is passed, you may **also** pass:
|
|
810
|
-
:param str style: Any valid CSL style in the Zotero style repository
|
|
811
|
-
:param str linkwrap: Set this to "1" to have URLs in bibliography entries (see below) wrapped in ``<a>`` tags.
|
|
812
|
-
:rtype: list of HTML strings or None.
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
.. note::
|
|
816
|
-
|
|
817
|
-
Any parameters you set will be valid **for the next call only**. Any parameters set using ``add_parameters()`` will be overridden by parameters you pass in the call itself.
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
A note on the ``content`` and ``style`` parameters:
|
|
821
|
-
|
|
822
|
-
Example:
|
|
823
|
-
|
|
824
|
-
.. code-block:: python
|
|
825
|
-
|
|
826
|
-
zot.add_parameters(content='bib', style='mla')
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
If these are set, the return value is a list of UTF-8 formatted HTML ``div`` elements, each containing an item:
|
|
830
|
-
|
|
831
|
-
``['<div class="csl-entry">(content)</div>']``.
|
|
832
|
-
|
|
833
|
-
You may also set ``content='citation'`` if you wish to retrieve citations. Similar to ``bib``, the result will be a list of one or more HTML ``span`` elements.
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
If you select one of the available `export formats <https://www.zotero.org/support/dev/web_api/v3/basics#export_formats>`_ as the ``content`` parameter, pyzotero will in most cases return a list of unicode strings in the format you specified. The exception is the ``csljson`` format, which is parsed into a list of dicts. Please note that you must provide a ``limit`` parameter if you specify one of these export formats. Multiple simultaneous retrieval of particular formats, e.g. ``content="json,coins"`` is not currently supported.
|
|
837
|
-
|
|
838
|
-
If you set ``format='keys'``, a newline-delimited string containing item keys will be returned
|
|
839
|
-
|
|
840
|
-
If you set ``format='bibtex'``, a `bibtexparser <https://bibtexparser.readthedocs.io/en/v0.6.2/bibtexparser.html#bibdatabase.BibDatabase.entries>`_ object containing citations will be returned. You can access the citations as a list of dicts using the ``.entries`` property. The bibtexparser object also implements a `dump method <https://bibtexparser.readthedocs.io/en/v0.6.2/bibtexparser.html#bibtexparser.dump>`_, if you'd like to write your citations to a ``.bib`` file.
|
|
841
|
-
|
|
842
|
-
|
|
843
822
|
.. _write:
|
|
844
823
|
|
|
824
|
+
=================
|
|
845
825
|
Write API Methods
|
|
846
826
|
=================
|
|
847
827
|
|
|
848
|
-
==============
|
|
849
828
|
Saved Searches
|
|
850
|
-
|
|
829
|
+
--------------
|
|
851
830
|
Pyzotero allows you to retrieve, delete, or modify saved searches:
|
|
852
831
|
|
|
853
832
|
.. py:method:: Zotero.searches()
|
|
@@ -891,9 +870,8 @@ Pyzotero allows you to retrieve, delete, or modify saved searches:
|
|
|
891
870
|
:param str condition: a valid saved search condition
|
|
892
871
|
:rtype: list
|
|
893
872
|
|
|
894
|
-
=================
|
|
895
873
|
Item Methods
|
|
896
|
-
|
|
874
|
+
------------
|
|
897
875
|
|
|
898
876
|
.. py:method:: Zotero.item_types()
|
|
899
877
|
|
|
@@ -936,7 +914,7 @@ Item Methods
|
|
|
936
914
|
:rtype: dict
|
|
937
915
|
|
|
938
916
|
Creating and Updating Items
|
|
939
|
-
|
|
917
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
940
918
|
|
|
941
919
|
.. py:method:: Zotero.create_items(items[, parentid, last_modified])
|
|
942
920
|
|
|
@@ -1010,7 +988,7 @@ Example:
|
|
|
1010
988
|
|
|
1011
989
|
|
|
1012
990
|
Uploading files
|
|
1013
|
-
|
|
991
|
+
~~~~~~~~~~~~~~~
|
|
1014
992
|
|
|
1015
993
|
.. warning:: Attachment methods are in beta.
|
|
1016
994
|
|
|
@@ -1054,7 +1032,7 @@ Uploading files
|
|
|
1054
1032
|
unlike the space-saving responses from the server, the return value here eschews the complex index / key lookup and simply passes back the ``imported_file`` item template populated with keys (if created successfully or passed in) corresponding to each result. This is the return type for all of these methods.
|
|
1055
1033
|
|
|
1056
1034
|
Deleting items
|
|
1057
|
-
|
|
1035
|
+
~~~~~~~~~~~~~~
|
|
1058
1036
|
|
|
1059
1037
|
.. py:method:: Zotero.delete_item(item[, last_modified])
|
|
1060
1038
|
|
|
@@ -1064,7 +1042,7 @@ Deleting items
|
|
|
1064
1042
|
:param str/int last_modified: If not ``None``, will set the value of the If-Unmodified-Since-Version header.
|
|
1065
1043
|
|
|
1066
1044
|
Deleting tags
|
|
1067
|
-
|
|
1045
|
+
~~~~~~~~~~~~~
|
|
1068
1046
|
|
|
1069
1047
|
.. py:method:: Zotero.delete_tags(tag_a[, tag …])
|
|
1070
1048
|
|
|
@@ -1074,9 +1052,8 @@ Deleting tags
|
|
|
1074
1052
|
|
|
1075
1053
|
You may also pass a list using ``zot.delete_tags(*[tag_list])``
|
|
1076
1054
|
|
|
1077
|
-
===========
|
|
1078
1055
|
Adding tags
|
|
1079
|
-
|
|
1056
|
+
-----------
|
|
1080
1057
|
|
|
1081
1058
|
.. py:method:: Zotero.add_tags(item, tag[, tag …])
|
|
1082
1059
|
|
|
@@ -1098,9 +1075,8 @@ Example:
|
|
|
1098
1075
|
# updated now contains a representation of the updated server item
|
|
1099
1076
|
|
|
1100
1077
|
|
|
1101
|
-
====================
|
|
1102
1078
|
Collection Methods
|
|
1103
|
-
|
|
1079
|
+
------------------
|
|
1104
1080
|
|
|
1105
1081
|
.. py:method:: Zotero.create_collections(dicts[, last_modified])
|
|
1106
1082
|
|
|
@@ -1180,17 +1156,20 @@ Examples:
|
|
|
1180
1156
|
|
|
1181
1157
|
|
|
1182
1158
|
|
|
1159
|
+
=====
|
|
1183
1160
|
Notes
|
|
1184
1161
|
=====
|
|
1185
1162
|
Most Read API methods return **lists** of **dicts** or, in the case of tag methods, **lists** of **strings**. Most Write API methods return either ``True`` if successful, or raise an error. See ``zotero_errors.py`` for a full listing of these.
|
|
1186
1163
|
|
|
1187
1164
|
.. warning:: URL parameters will supersede API calls which should return e.g. a single item: ``https://api.zotero.org/users/436/items/ABC?start=50&limit=10`` will return 10 items beginning at position 50, even though ``ABC`` does not exist. Be aware of this, and don't pass URL parameters which do not apply to a given API method.
|
|
1188
1165
|
|
|
1166
|
+
=======
|
|
1189
1167
|
License
|
|
1190
1168
|
=======
|
|
1191
1169
|
Pyzotero is licensed under the `Blue Oak Model Licence <https://opensource.org/license/blue-oak-model-license>`_ license.
|
|
1192
1170
|
|
|
1193
1171
|
|
|
1172
|
+
===========
|
|
1194
1173
|
Cat Picture
|
|
1195
1174
|
===========
|
|
1196
1175
|
This is The Grinch.
|
|
@@ -796,12 +796,12 @@ class Zotero:
|
|
|
796
796
|
"""Dump a file attachment to disk, with optional filename and path"""
|
|
797
797
|
if not filename:
|
|
798
798
|
filename = self.item(itemkey)["data"]["filename"]
|
|
799
|
-
pth = Path(path) / filename if path else filename
|
|
799
|
+
pth = Path(path) / filename if path else Path(filename)
|
|
800
800
|
file = self.file(itemkey)
|
|
801
801
|
if self.snapshot:
|
|
802
802
|
self.snapshot = False
|
|
803
|
-
pth
|
|
804
|
-
with
|
|
803
|
+
pth = pth.parent / (pth.name + ".zip")
|
|
804
|
+
with pth.open("wb") as f:
|
|
805
805
|
f.write(file)
|
|
806
806
|
|
|
807
807
|
@retrieve
|
|
@@ -1492,7 +1492,7 @@ class Zotero:
|
|
|
1492
1492
|
|
|
1493
1493
|
@backoff_check
|
|
1494
1494
|
def addto_collection(self, collection, payload):
|
|
1495
|
-
"""Add
|
|
1495
|
+
"""Add item to a collection
|
|
1496
1496
|
Accepts two arguments:
|
|
1497
1497
|
The collection ID, and an item dict
|
|
1498
1498
|
"""
|
|
@@ -1879,6 +1879,12 @@ class Zupload:
|
|
|
1879
1879
|
msg,
|
|
1880
1880
|
)
|
|
1881
1881
|
return None # Don't do anything if payload comes with keys
|
|
1882
|
+
# Set contentType for each attachment if not already provided
|
|
1883
|
+
for item in self.payload:
|
|
1884
|
+
if not item.get("contentType"):
|
|
1885
|
+
filepath = str(self.basedir.joinpath(item["filename"]))
|
|
1886
|
+
detected_type = mimetypes.guess_type(filepath)[0]
|
|
1887
|
+
item["contentType"] = detected_type or "application/octet-stream"
|
|
1882
1888
|
liblevel = "/{t}/{u}/items"
|
|
1883
1889
|
# Create one or more new attachments
|
|
1884
1890
|
headers = {"Zotero-Write-Token": token(), "Content-Type": "application/json"}
|
|
@@ -1156,6 +1156,110 @@ class ZoteroTests(unittest.TestCase):
|
|
|
1156
1156
|
# Clean up
|
|
1157
1157
|
os.remove(temp_file_path)
|
|
1158
1158
|
|
|
1159
|
+
@httpretty.activate
|
|
1160
|
+
def testFileUploadSetsContentType(self):
|
|
1161
|
+
"""Tests that contentType is automatically set during upload based on file extension"""
|
|
1162
|
+
zot = z.Zotero("myuserID", "user", "myuserkey")
|
|
1163
|
+
|
|
1164
|
+
# Create a temporary PDF file for testing
|
|
1165
|
+
temp_file_path = os.path.join(self.cwd, "api_responses", "test_upload.pdf")
|
|
1166
|
+
with open(temp_file_path, "w") as f:
|
|
1167
|
+
f.write("Fake PDF content")
|
|
1168
|
+
|
|
1169
|
+
# Variable to capture the request body
|
|
1170
|
+
captured_body = []
|
|
1171
|
+
|
|
1172
|
+
def request_callback(request, uri, response_headers):
|
|
1173
|
+
body = json.loads(request.body)
|
|
1174
|
+
captured_body.append(body)
|
|
1175
|
+
return [200, response_headers, json.dumps({"success": {"0": "ITEMKEY123"}})]
|
|
1176
|
+
|
|
1177
|
+
HTTPretty.register_uri(
|
|
1178
|
+
HTTPretty.POST,
|
|
1179
|
+
"https://api.zotero.org/users/myuserID/items",
|
|
1180
|
+
body=request_callback,
|
|
1181
|
+
content_type="application/json",
|
|
1182
|
+
)
|
|
1183
|
+
|
|
1184
|
+
# Create payload with empty contentType (mimics Zotero API template)
|
|
1185
|
+
payload = [
|
|
1186
|
+
{
|
|
1187
|
+
"filename": "test_upload.pdf",
|
|
1188
|
+
"title": "Test PDF",
|
|
1189
|
+
"linkMode": "imported_file",
|
|
1190
|
+
"contentType": "",
|
|
1191
|
+
}
|
|
1192
|
+
]
|
|
1193
|
+
|
|
1194
|
+
mock_auth_data = {"exists": True}
|
|
1195
|
+
|
|
1196
|
+
with (
|
|
1197
|
+
patch.object(z.Zupload, "_verify", return_value=None),
|
|
1198
|
+
patch.object(z.Zupload, "_get_auth", return_value=mock_auth_data),
|
|
1199
|
+
):
|
|
1200
|
+
upload = z.Zupload(
|
|
1201
|
+
zot, payload, basedir=os.path.join(self.cwd, "api_responses")
|
|
1202
|
+
)
|
|
1203
|
+
upload.upload()
|
|
1204
|
+
|
|
1205
|
+
# Verify contentType was automatically set to application/pdf
|
|
1206
|
+
self.assertEqual(len(captured_body), 1)
|
|
1207
|
+
self.assertEqual(captured_body[0][0].get("contentType"), "application/pdf")
|
|
1208
|
+
|
|
1209
|
+
os.remove(temp_file_path)
|
|
1210
|
+
|
|
1211
|
+
@httpretty.activate
|
|
1212
|
+
def testFileUploadPreservesUserContentType(self):
|
|
1213
|
+
"""Tests that user-provided contentType is not overridden"""
|
|
1214
|
+
zot = z.Zotero("myuserID", "user", "myuserkey")
|
|
1215
|
+
|
|
1216
|
+
temp_file_path = os.path.join(self.cwd, "api_responses", "test_upload.txt")
|
|
1217
|
+
with open(temp_file_path, "w") as f:
|
|
1218
|
+
f.write("Test content")
|
|
1219
|
+
|
|
1220
|
+
captured_body = []
|
|
1221
|
+
|
|
1222
|
+
def request_callback(request, uri, response_headers):
|
|
1223
|
+
body = json.loads(request.body)
|
|
1224
|
+
captured_body.append(body)
|
|
1225
|
+
return [200, response_headers, json.dumps({"success": {"0": "ITEMKEY123"}})]
|
|
1226
|
+
|
|
1227
|
+
HTTPretty.register_uri(
|
|
1228
|
+
HTTPretty.POST,
|
|
1229
|
+
"https://api.zotero.org/users/myuserID/items",
|
|
1230
|
+
body=request_callback,
|
|
1231
|
+
content_type="application/json",
|
|
1232
|
+
)
|
|
1233
|
+
|
|
1234
|
+
# Create payload WITH explicit contentType
|
|
1235
|
+
payload = [
|
|
1236
|
+
{
|
|
1237
|
+
"filename": "test_upload.txt",
|
|
1238
|
+
"title": "Test File",
|
|
1239
|
+
"linkMode": "imported_file",
|
|
1240
|
+
"contentType": "application/custom-type",
|
|
1241
|
+
}
|
|
1242
|
+
]
|
|
1243
|
+
|
|
1244
|
+
mock_auth_data = {"exists": True}
|
|
1245
|
+
|
|
1246
|
+
with (
|
|
1247
|
+
patch.object(z.Zupload, "_verify", return_value=None),
|
|
1248
|
+
patch.object(z.Zupload, "_get_auth", return_value=mock_auth_data),
|
|
1249
|
+
):
|
|
1250
|
+
upload = z.Zupload(
|
|
1251
|
+
zot, payload, basedir=os.path.join(self.cwd, "api_responses")
|
|
1252
|
+
)
|
|
1253
|
+
upload.upload()
|
|
1254
|
+
|
|
1255
|
+
# Verify user-provided contentType was preserved
|
|
1256
|
+
self.assertEqual(len(captured_body), 1)
|
|
1257
|
+
self.assertEqual(
|
|
1258
|
+
captured_body[0][0].get("contentType"), "application/custom-type"
|
|
1259
|
+
)
|
|
1260
|
+
|
|
1261
|
+
os.remove(temp_file_path)
|
|
1262
|
+
|
|
1159
1263
|
@httpretty.activate
|
|
1160
1264
|
def testFileUploadWithPreexistingKeys(self):
|
|
1161
1265
|
"""Tests file upload process when the payload already contains keys"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|