pyzotero 1.6.17__py3-none-any.whl → 1.7.1__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/cli.py +352 -0
- pyzotero/zotero.py +5 -6
- {pyzotero-1.6.17.dist-info → pyzotero-1.7.1.dist-info}/METADATA +72 -1
- pyzotero-1.7.1.dist-info/RECORD +9 -0
- {pyzotero-1.6.17.dist-info → pyzotero-1.7.1.dist-info}/WHEEL +1 -1
- pyzotero-1.7.1.dist-info/entry_points.txt +3 -0
- pyzotero-1.6.17.dist-info/RECORD +0 -7
pyzotero/cli.py
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"""Command-line interface for pyzotero."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from pyzotero import zotero
|
|
9
|
+
from pyzotero.zotero import chunks
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _get_zotero_client(locale="en-US"):
|
|
13
|
+
"""Get a Zotero client configured for local access."""
|
|
14
|
+
return zotero.Zotero(library_id="0", library_type="user", local=True, locale=locale)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.group()
|
|
18
|
+
@click.option(
|
|
19
|
+
"--locale",
|
|
20
|
+
default="en-US",
|
|
21
|
+
help="Locale for localized strings (default: en-US)",
|
|
22
|
+
)
|
|
23
|
+
@click.pass_context
|
|
24
|
+
def main(ctx, locale):
|
|
25
|
+
"""Search local Zotero library."""
|
|
26
|
+
ctx.ensure_object(dict)
|
|
27
|
+
ctx.obj["locale"] = locale
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@main.command()
|
|
31
|
+
@click.option(
|
|
32
|
+
"-q",
|
|
33
|
+
"--query",
|
|
34
|
+
help="Search query string",
|
|
35
|
+
default="",
|
|
36
|
+
)
|
|
37
|
+
@click.option(
|
|
38
|
+
"--fulltext",
|
|
39
|
+
is_flag=True,
|
|
40
|
+
help="Search full-text content including PDFs. Retrieves parent items when attachments match.",
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--itemtype",
|
|
44
|
+
multiple=True,
|
|
45
|
+
help="Filter by item type (can be specified multiple times for OR search)",
|
|
46
|
+
)
|
|
47
|
+
@click.option(
|
|
48
|
+
"--collection",
|
|
49
|
+
help="Filter by collection key (returns only items in this collection)",
|
|
50
|
+
)
|
|
51
|
+
@click.option(
|
|
52
|
+
"--limit",
|
|
53
|
+
type=int,
|
|
54
|
+
default=1000000,
|
|
55
|
+
help="Maximum number of results to return (default: 1000000)",
|
|
56
|
+
)
|
|
57
|
+
@click.option(
|
|
58
|
+
"--json",
|
|
59
|
+
"output_json",
|
|
60
|
+
is_flag=True,
|
|
61
|
+
help="Output results as JSON",
|
|
62
|
+
)
|
|
63
|
+
@click.pass_context
|
|
64
|
+
def search(ctx, query, fulltext, itemtype, collection, limit, output_json): # noqa: PLR0912, PLR0915
|
|
65
|
+
"""Search local Zotero library.
|
|
66
|
+
|
|
67
|
+
By default, searches top-level items in titles and metadata.
|
|
68
|
+
|
|
69
|
+
When --fulltext is enabled, searches all items including attachment content
|
|
70
|
+
(PDFs, documents, etc.). If a match is found in an attachment, the parent
|
|
71
|
+
bibliographic item is retrieved and included in results.
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
pyzotero search -q "machine learning"
|
|
75
|
+
|
|
76
|
+
pyzotero search -q "climate change" --fulltext
|
|
77
|
+
|
|
78
|
+
pyzotero search -q "methodology" --itemtype book --itemtype journalArticle
|
|
79
|
+
|
|
80
|
+
pyzotero search --collection ABC123 -q "test"
|
|
81
|
+
|
|
82
|
+
pyzotero search -q "climate" --json
|
|
83
|
+
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
locale = ctx.obj.get("locale", "en-US")
|
|
87
|
+
zot = _get_zotero_client(locale)
|
|
88
|
+
|
|
89
|
+
# Build query parameters
|
|
90
|
+
params = {"limit": limit}
|
|
91
|
+
|
|
92
|
+
if query:
|
|
93
|
+
params["q"] = query
|
|
94
|
+
|
|
95
|
+
if fulltext:
|
|
96
|
+
params["qmode"] = "everything"
|
|
97
|
+
|
|
98
|
+
if itemtype:
|
|
99
|
+
# Join multiple item types with || for OR search
|
|
100
|
+
params["itemType"] = " || ".join(itemtype)
|
|
101
|
+
|
|
102
|
+
# Execute search
|
|
103
|
+
# When fulltext is enabled, use items() or collection_items() to get both
|
|
104
|
+
# top-level items and attachments. Otherwise use top() or collection_items_top()
|
|
105
|
+
# to only get top-level items.
|
|
106
|
+
if fulltext:
|
|
107
|
+
if collection:
|
|
108
|
+
results = zot.collection_items(collection, **params)
|
|
109
|
+
else:
|
|
110
|
+
results = zot.items(**params)
|
|
111
|
+
|
|
112
|
+
# When using fulltext, we need to retrieve parent items for any attachments
|
|
113
|
+
# that matched, since most full-text content comes from PDFs and other attachments
|
|
114
|
+
top_level_items = []
|
|
115
|
+
attachment_items = []
|
|
116
|
+
|
|
117
|
+
for item in results:
|
|
118
|
+
data = item.get("data", {})
|
|
119
|
+
if "parentItem" in data:
|
|
120
|
+
attachment_items.append(item)
|
|
121
|
+
else:
|
|
122
|
+
top_level_items.append(item)
|
|
123
|
+
|
|
124
|
+
# Retrieve parent items for attachments in batches of 50
|
|
125
|
+
parent_items = []
|
|
126
|
+
if attachment_items:
|
|
127
|
+
parent_ids = list(
|
|
128
|
+
{item["data"]["parentItem"] for item in attachment_items}
|
|
129
|
+
)
|
|
130
|
+
for chunk in chunks(parent_ids, 50):
|
|
131
|
+
parent_items.extend(zot.get_subset(chunk))
|
|
132
|
+
|
|
133
|
+
# Combine top-level items and parent items, removing duplicates by key
|
|
134
|
+
all_items = top_level_items + parent_items
|
|
135
|
+
items_dict = {item["data"]["key"]: item for item in all_items}
|
|
136
|
+
results = list(items_dict.values())
|
|
137
|
+
# Non-fulltext search: use top() or collection_items_top() as before
|
|
138
|
+
elif collection:
|
|
139
|
+
results = zot.collection_items_top(collection, **params)
|
|
140
|
+
else:
|
|
141
|
+
results = zot.top(**params)
|
|
142
|
+
|
|
143
|
+
# Handle empty results
|
|
144
|
+
if not results:
|
|
145
|
+
if output_json:
|
|
146
|
+
click.echo(json.dumps([]))
|
|
147
|
+
else:
|
|
148
|
+
click.echo("No results found.")
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
# Build output data structure
|
|
152
|
+
output_items = []
|
|
153
|
+
for item in results:
|
|
154
|
+
data = item.get("data", {})
|
|
155
|
+
|
|
156
|
+
title = data.get("title", "No title")
|
|
157
|
+
item_type = data.get("itemType", "Unknown")
|
|
158
|
+
date = data.get("date", "No date")
|
|
159
|
+
item_key = data.get("key", "")
|
|
160
|
+
publication = data.get("publicationTitle", "")
|
|
161
|
+
volume = data.get("volume", "")
|
|
162
|
+
issue = data.get("issue", "")
|
|
163
|
+
doi = data.get("DOI", "")
|
|
164
|
+
url = data.get("url", "")
|
|
165
|
+
|
|
166
|
+
# Format creators (authors, editors, etc.)
|
|
167
|
+
creators = data.get("creators", [])
|
|
168
|
+
creator_names = []
|
|
169
|
+
for creator in creators:
|
|
170
|
+
if "lastName" in creator:
|
|
171
|
+
if "firstName" in creator:
|
|
172
|
+
creator_names.append(
|
|
173
|
+
f"{creator['firstName']} {creator['lastName']}"
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
creator_names.append(creator["lastName"])
|
|
177
|
+
elif "name" in creator:
|
|
178
|
+
creator_names.append(creator["name"])
|
|
179
|
+
|
|
180
|
+
# Check for PDF attachments
|
|
181
|
+
pdf_attachments = []
|
|
182
|
+
num_children = item.get("meta", {}).get("numChildren", 0)
|
|
183
|
+
if num_children > 0:
|
|
184
|
+
children = zot.children(item_key)
|
|
185
|
+
for child in children:
|
|
186
|
+
child_data = child.get("data", {})
|
|
187
|
+
if child_data.get("contentType") == "application/pdf":
|
|
188
|
+
# Extract file URL from links.enclosure.href
|
|
189
|
+
file_url = (
|
|
190
|
+
child.get("links", {}).get("enclosure", {}).get("href", "")
|
|
191
|
+
)
|
|
192
|
+
if file_url:
|
|
193
|
+
pdf_attachments.append(file_url)
|
|
194
|
+
|
|
195
|
+
# Build item object for JSON output
|
|
196
|
+
item_obj = {
|
|
197
|
+
"key": item_key,
|
|
198
|
+
"itemType": item_type,
|
|
199
|
+
"title": title,
|
|
200
|
+
"creators": creator_names,
|
|
201
|
+
"date": date,
|
|
202
|
+
"publication": publication,
|
|
203
|
+
"volume": volume,
|
|
204
|
+
"issue": issue,
|
|
205
|
+
"doi": doi,
|
|
206
|
+
"url": url,
|
|
207
|
+
"pdfAttachments": pdf_attachments,
|
|
208
|
+
}
|
|
209
|
+
output_items.append(item_obj)
|
|
210
|
+
|
|
211
|
+
# Output results
|
|
212
|
+
if output_json:
|
|
213
|
+
click.echo(json.dumps(output_items, indent=2))
|
|
214
|
+
else:
|
|
215
|
+
click.echo(f"\nFound {len(results)} items:\n")
|
|
216
|
+
for idx, item_obj in enumerate(output_items, 1):
|
|
217
|
+
authors_str = (
|
|
218
|
+
", ".join(item_obj["creators"])
|
|
219
|
+
if item_obj["creators"]
|
|
220
|
+
else "No authors"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
click.echo(f"{idx}. [{item_obj['itemType']}] {item_obj['title']}")
|
|
224
|
+
click.echo(f" Authors: {authors_str}")
|
|
225
|
+
click.echo(f" Date: {item_obj['date']}")
|
|
226
|
+
click.echo(f" Publication: {item_obj['publication']}")
|
|
227
|
+
click.echo(f" Volume: {item_obj['volume']}")
|
|
228
|
+
click.echo(f" Issue: {item_obj['issue']}")
|
|
229
|
+
click.echo(f" DOI: {item_obj['doi']}")
|
|
230
|
+
click.echo(f" URL: {item_obj['url']}")
|
|
231
|
+
click.echo(f" Key: {item_obj['key']}")
|
|
232
|
+
|
|
233
|
+
if item_obj["pdfAttachments"]:
|
|
234
|
+
click.echo(" PDF Attachments:")
|
|
235
|
+
for pdf_url in item_obj["pdfAttachments"]:
|
|
236
|
+
click.echo(f" {pdf_url}")
|
|
237
|
+
|
|
238
|
+
click.echo()
|
|
239
|
+
|
|
240
|
+
except Exception as e:
|
|
241
|
+
click.echo(f"Error: {e!s}", err=True)
|
|
242
|
+
sys.exit(1)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@main.command()
|
|
246
|
+
@click.option(
|
|
247
|
+
"--limit",
|
|
248
|
+
type=int,
|
|
249
|
+
help="Maximum number of collections to return (default: all)",
|
|
250
|
+
)
|
|
251
|
+
@click.pass_context
|
|
252
|
+
def listcollections(ctx, limit):
|
|
253
|
+
"""List all collections in the local Zotero library.
|
|
254
|
+
|
|
255
|
+
Examples:
|
|
256
|
+
pyzotero listcollections
|
|
257
|
+
|
|
258
|
+
pyzotero listcollections --limit 10
|
|
259
|
+
|
|
260
|
+
"""
|
|
261
|
+
try:
|
|
262
|
+
locale = ctx.obj.get("locale", "en-US")
|
|
263
|
+
zot = _get_zotero_client(locale)
|
|
264
|
+
|
|
265
|
+
# Build query parameters
|
|
266
|
+
params = {}
|
|
267
|
+
if limit:
|
|
268
|
+
params["limit"] = limit
|
|
269
|
+
|
|
270
|
+
# Get all collections
|
|
271
|
+
collections = zot.collections(**params)
|
|
272
|
+
|
|
273
|
+
if not collections:
|
|
274
|
+
click.echo(json.dumps([]))
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
# Build a mapping of collection keys to names for parent lookup
|
|
278
|
+
collection_map = {}
|
|
279
|
+
for collection in collections:
|
|
280
|
+
data = collection.get("data", {})
|
|
281
|
+
key = data.get("key", "")
|
|
282
|
+
name = data.get("name", "")
|
|
283
|
+
if key:
|
|
284
|
+
collection_map[key] = name if name else None
|
|
285
|
+
|
|
286
|
+
# Build JSON output
|
|
287
|
+
output = []
|
|
288
|
+
for collection in collections:
|
|
289
|
+
data = collection.get("data", {})
|
|
290
|
+
meta = collection.get("meta", {})
|
|
291
|
+
|
|
292
|
+
name = data.get("name", "")
|
|
293
|
+
key = data.get("key", "")
|
|
294
|
+
num_items = meta.get("numItems", 0)
|
|
295
|
+
parent_collection = data.get("parentCollection", "")
|
|
296
|
+
|
|
297
|
+
collection_obj = {
|
|
298
|
+
"id": key,
|
|
299
|
+
"name": name if name else None,
|
|
300
|
+
"items": num_items,
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
# Add parent information if it exists
|
|
304
|
+
if parent_collection:
|
|
305
|
+
parent_name = collection_map.get(parent_collection)
|
|
306
|
+
collection_obj["parent"] = {
|
|
307
|
+
"id": parent_collection,
|
|
308
|
+
"name": parent_name,
|
|
309
|
+
}
|
|
310
|
+
else:
|
|
311
|
+
collection_obj["parent"] = None
|
|
312
|
+
|
|
313
|
+
output.append(collection_obj)
|
|
314
|
+
|
|
315
|
+
# Output as JSON
|
|
316
|
+
click.echo(json.dumps(output, indent=2))
|
|
317
|
+
|
|
318
|
+
except Exception as e:
|
|
319
|
+
click.echo(f"Error: {e!s}", err=True)
|
|
320
|
+
sys.exit(1)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@main.command()
|
|
324
|
+
@click.pass_context
|
|
325
|
+
def itemtypes(ctx):
|
|
326
|
+
"""List all valid item types.
|
|
327
|
+
|
|
328
|
+
Examples:
|
|
329
|
+
pyzotero itemtypes
|
|
330
|
+
|
|
331
|
+
"""
|
|
332
|
+
try:
|
|
333
|
+
locale = ctx.obj.get("locale", "en-US")
|
|
334
|
+
zot = _get_zotero_client(locale)
|
|
335
|
+
|
|
336
|
+
# Get all item types
|
|
337
|
+
item_types = zot.item_types()
|
|
338
|
+
|
|
339
|
+
if not item_types:
|
|
340
|
+
click.echo(json.dumps([]))
|
|
341
|
+
return
|
|
342
|
+
|
|
343
|
+
# Output as JSON array
|
|
344
|
+
click.echo(json.dumps(item_types, indent=2))
|
|
345
|
+
|
|
346
|
+
except Exception as e:
|
|
347
|
+
click.echo(f"Error: {e!s}", err=True)
|
|
348
|
+
sys.exit(1)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
if __name__ == "__main__":
|
|
352
|
+
main()
|
pyzotero/zotero.py
CHANGED
|
@@ -51,14 +51,13 @@ DEFAULT_ITEM_LIMIT = 100
|
|
|
51
51
|
def build_url(base_url, path, args_dict=None):
|
|
52
52
|
"""Build a valid URL so we don't have to worry about string concatenation errors and
|
|
53
53
|
leading / trailing slashes etc.
|
|
54
|
-
Returns a list in the structure of urlparse.ParseResult
|
|
55
54
|
"""
|
|
56
55
|
base_url = base_url.removesuffix("/")
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
parsed = urlparse(base_url)
|
|
57
|
+
new_path = str(PurePosixPath(parsed.path) / path.removeprefix("/"))
|
|
59
58
|
if args_dict:
|
|
60
|
-
|
|
61
|
-
return urlunparse(
|
|
59
|
+
return urlunparse(parsed._replace(path=new_path, query=urlencode(args_dict)))
|
|
60
|
+
return urlunparse(parsed._replace(path=new_path))
|
|
62
61
|
|
|
63
62
|
|
|
64
63
|
def merge_params(url, params):
|
|
@@ -513,7 +512,7 @@ class Zotero:
|
|
|
513
512
|
try:
|
|
514
513
|
for key, value in self.request.links.items():
|
|
515
514
|
parsed = urlparse(value["url"])
|
|
516
|
-
fragment =
|
|
515
|
+
fragment = urlunparse(("", "", parsed.path, "", parsed.query, ""))
|
|
517
516
|
extracted[key] = fragment
|
|
518
517
|
# add a 'self' link
|
|
519
518
|
parsed = urlparse(str(self.self_link))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: pyzotero
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.1
|
|
4
4
|
Summary: Python wrapper for the Zotero API
|
|
5
5
|
Keywords: Zotero,DH
|
|
6
6
|
Author: Stephan Hügel
|
|
@@ -57,10 +57,12 @@ Requires-Dist: feedparser>=6.0.12
|
|
|
57
57
|
Requires-Dist: bibtexparser>=1.4.3,<2.0.0
|
|
58
58
|
Requires-Dist: httpx>=0.28.1
|
|
59
59
|
Requires-Dist: whenever>=0.8.8
|
|
60
|
+
Requires-Dist: click>=8.0.0 ; extra == 'cli'
|
|
60
61
|
Requires-Python: >=3.9
|
|
61
62
|
Project-URL: Repository, https://github.com/urschrei/pyzotero
|
|
62
63
|
Project-URL: Tracker, https://github.com/urschrei/pyzotero/issues
|
|
63
64
|
Project-URL: documentation, https://pyzotero.readthedocs.org
|
|
65
|
+
Provides-Extra: cli
|
|
64
66
|
Description-Content-Type: text/markdown
|
|
65
67
|
|
|
66
68
|
[](https://pypi.python.org/pypi/Pyzotero/) [](http://pyzotero.readthedocs.org/en/latest/?badge=latest) [](https://pypi.python.org/pypi/Pyzotero) [](https://anaconda.org/conda-forge/pyzotero) [](https://pepy.tech/project/pyzotero)
|
|
@@ -93,11 +95,80 @@ for item in items:
|
|
|
93
95
|
|
|
94
96
|
Full documentation of available Pyzotero methods, code examples, and sample output is available on [Read The Docs][3].
|
|
95
97
|
|
|
98
|
+
# Command-Line Interface
|
|
99
|
+
|
|
100
|
+
Pyzotero includes an optional command-line interface for searching and querying your local Zotero library. The CLI must be installed separately (see [Installation](#optional-command-line-interface)).
|
|
101
|
+
|
|
102
|
+
## Basic Usage
|
|
103
|
+
|
|
104
|
+
The CLI connects to your local Zotero installation and allows you to search your library, list collections, and view item types:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Search for top-level items
|
|
108
|
+
pyzotero search -q "machine learning"
|
|
109
|
+
|
|
110
|
+
# Search with full-text mode
|
|
111
|
+
pyzotero search -q "climate change" --fulltext
|
|
112
|
+
|
|
113
|
+
# Filter by item type
|
|
114
|
+
pyzotero search -q "methodology" --itemtype book --itemtype journalArticle
|
|
115
|
+
|
|
116
|
+
# Search for top-level items within a collection
|
|
117
|
+
pyzotero search --collection ABC123 -q "test"
|
|
118
|
+
|
|
119
|
+
# Output as JSON for machine processing
|
|
120
|
+
pyzotero search -q "climate" --json
|
|
121
|
+
|
|
122
|
+
# List all collections
|
|
123
|
+
pyzotero listcollections
|
|
124
|
+
|
|
125
|
+
# List available item types
|
|
126
|
+
pyzotero itemtypes
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Search Behaviour
|
|
130
|
+
|
|
131
|
+
By default, `pyzotero search` searches only top-level item titles and metadata fields.
|
|
132
|
+
|
|
133
|
+
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.
|
|
134
|
+
|
|
135
|
+
## Output Format
|
|
136
|
+
|
|
137
|
+
By default, the CLI outputs human-readable text with a subset of metadata including:
|
|
138
|
+
- Title, authors, date, publication
|
|
139
|
+
- Volume, issue, DOI, URL
|
|
140
|
+
- PDF attachments (with local file paths)
|
|
141
|
+
|
|
142
|
+
Use the `--json` flag to output structured JSON.
|
|
143
|
+
|
|
96
144
|
# Installation
|
|
97
145
|
|
|
98
146
|
* Using [uv][11]: `uv add pyzotero`
|
|
99
147
|
* Using [pip][10]: `pip install pyzotero`
|
|
100
148
|
* Using Anaconda:`conda install conda-forge::pyzotero`
|
|
149
|
+
|
|
150
|
+
## Optional: Command-Line Interface
|
|
151
|
+
|
|
152
|
+
Pyzotero includes an optional command-line interface for searching and querying your local Zotero library.
|
|
153
|
+
|
|
154
|
+
### Installing the CLI
|
|
155
|
+
|
|
156
|
+
To install Pyzotero with the CLI:
|
|
157
|
+
|
|
158
|
+
* Using [uv][11]: `uv add "pyzotero[cli]"`
|
|
159
|
+
* Using [pip][10]: `pip install "pyzotero[cli]"`
|
|
160
|
+
|
|
161
|
+
### Using the CLI without installing
|
|
162
|
+
|
|
163
|
+
If you just want to use the CLI without permanently installing Pyzotero, you can run it directly:
|
|
164
|
+
|
|
165
|
+
* Using [uvx][11]: `uvx --from "pyzotero[cli]" pyzotero search -q "your query"`
|
|
166
|
+
* Using [pipx][10]: `pipx run --spec "pyzotero[cli]" pyzotero search -q "your query"`
|
|
167
|
+
|
|
168
|
+
See the [Command-Line Interface](#command-line-interface) section below for usage details.
|
|
169
|
+
|
|
170
|
+
## Installing from Source
|
|
171
|
+
|
|
101
172
|
* From a local clone, if you wish to install Pyzotero from a specific branch:
|
|
102
173
|
|
|
103
174
|
Example:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
pyzotero/__init__.py,sha256=5QI4Jou9L-YJAf_oN9TgRXVKgt_Unc39oADo2Ch8bLI,243
|
|
2
|
+
pyzotero/cli.py,sha256=4vWX8SobVoHouJ1k7cumqtuWKqeFPPp5QyZzfdzBDOc,11023
|
|
3
|
+
pyzotero/filetransport.py,sha256=umLik1LLmrpgaNmyjvtBoqqcaMgIq79PYsTvN5vG-gY,5530
|
|
4
|
+
pyzotero/zotero.py,sha256=4qb7jLl1lNkDv3WpEPLW2L0SbleTtGYlQ6Rloz-hmN0,76497
|
|
5
|
+
pyzotero/zotero_errors.py,sha256=6obx9-pBO0z1bxt33vuzDluELvA5kSLCsfc-uGc3KNw,2660
|
|
6
|
+
pyzotero-1.7.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
7
|
+
pyzotero-1.7.1.dist-info/entry_points.txt,sha256=MzN7IMRj_oPNmDCsseYFPum3bHWE1gFxywhlbFbcn2k,48
|
|
8
|
+
pyzotero-1.7.1.dist-info/METADATA,sha256=-fxVGQetAnFkecnXs67FhGSJfsbL9i_a7VOMg7_Rz2c,9776
|
|
9
|
+
pyzotero-1.7.1.dist-info/RECORD,,
|
pyzotero-1.6.17.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=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,,
|