Skill Tracer
Skills › Scientific Agent Skills › pyzotero › files-attachments.md

files-attachments.md

107 lines · skills/pyzotero/references/files-attachments.md at 5f2bc03

Open on GitHub
1# Files & Attachments
2

Files & Attachments

Raw lines 1 to 2
3## Downloading Files
4
5```python
6# Get raw binary content of an attachment
7raw = zot.file('ATTACHMENTKEY')
8with open('paper.pdf', 'wb') as f:
9 f.write(raw)
11# Convenient wrapper: dump file to disk
12# Uses stored filename, saves to current directory
13zot.dump('ATTACHMENTKEY')
15# Dump to a specific path and filename
16zot.dump('ATTACHMENTKEY', 'renamed_paper.pdf', 'papers')
17# Create the directory first. Returns None on success, not a path.
18```
20`dump()` uses the provided filename or stored attachment filename. For responses classified as HTML snapshots, 1.15.2 appends `.zip` to that name; ZIP/EPUB handling can return an archive member. Verify the saved bytes and type instead of assuming every snapshot is a ZIP or is named with its key. Remote `/file` downloads require stored, synced files and appropriate permissions; linked files are not uploaded to Zotero storage.

Downloading Files

# Get raw binary content of an attachment
raw = zot.file('ATTACHMENTKEY')
with open('paper.pdf', 'wb') as f:
    f.write(raw)

# Convenient wrapper: dump file to disk
# Uses stored filename, saves to current directory
zot.dump('ATTACHMENTKEY')

# Dump to a specific path and filename
zot.dump('ATTACHMENTKEY', 'renamed_paper.pdf', 'papers')
# Create the directory first. Returns None on success, not a path.

dump() uses the provided filename or stored attachment filename. For responses classified as HTML snapshots, 1.15.2 appends .zip to that name; ZIP/EPUB handling can return an archive member. Verify the saved bytes and type instead of assuming every snapshot is a ZIP or is named with its key. Remote /file downloads require stored, synced files and appropriate permissions; linked files are not uploaded to Zotero storage.

Raw lines 3 to 21
22## Finding Attachments
24```python
25# Get child items (attachments, notes) of a parent item
26children = zot.children('PARENTKEY')
27attachments = [c for c in children if c['data']['itemType'] == 'attachment']
29# Get the attachment key
30for att in attachments:
31 key = att['data']['key']
32 filename = att['data'].get('filename') # absent on linked URLs
33 content_type = att['data']['contentType']
34 link_mode = att['data']['linkMode'] # 'imported_file', 'linked_file', 'imported_url', 'linked_url'
35```

Finding Attachments

# Get child items (attachments, notes) of a parent item
children = zot.children('PARENTKEY')
attachments = [c for c in children if c['data']['itemType'] == 'attachment']

# Get the attachment key
for att in attachments:
    key = att['data']['key']
    filename = att['data'].get('filename')  # absent on linked URLs
    content_type = att['data']['contentType']
    link_mode = att['data']['linkMode']  # 'imported_file', 'linked_file', 'imported_url', 'linked_url'
Raw lines 22 to 36
37## Uploading Attachments
39**Note**: Upstream still labels attachment helpers beta. The simple/both helpers below require the remote API; local uploads need a manually built attachment dict and Zotero 10+ authorization (see [authentication.md](authentication.md)).
41```python
42# Simple upload: one or more files by path
43result = zot.attachment_simple(['/path/to/paper.pdf', '/path/to/notes.docx'])
45# Upload as child items of a parent
46result = zot.attachment_simple(['/path/to/paper.pdf'], parentid='PARENTKEY')
48# Upload with custom filenames: list of (name, path) tuples
49result = zot.attachment_both([
50 ('Paper 2024.pdf', '/path/to/paper.pdf'),
51 ('Supplementary.pdf', '/path/to/supp.pdf'),
52], parentid='PARENTKEY')
54# Upload files to existing attachment items
55result = zot.upload_attachments(attachment_items, basedir='/path/to/files/')
56# Existing entries need editable attachment dicts with key + version;
57# filename resolves on disk relative to basedir. Do not set parentid for existing items.
58if result['failure']:
59 raise RuntimeError(result['failure'])
60```
62Upload result structure:
63```python
65 'success': [attachment_item1, ...],
66 'failure': [attachment_item2, ...],
67 'unchanged': [attachment_item3, ...]
69```

Uploading Attachments

Note: Upstream still labels attachment helpers beta. The simple/both helpers below require the remote API; local uploads need a manually built attachment dict and Zotero 10+ authorization (see authentication.md).

# Simple upload: one or more files by path
result = zot.attachment_simple(['/path/to/paper.pdf', '/path/to/notes.docx'])

# Upload as child items of a parent
result = zot.attachment_simple(['/path/to/paper.pdf'], parentid='PARENTKEY')

# Upload with custom filenames: list of (name, path) tuples
result = zot.attachment_both([
    ('Paper 2024.pdf', '/path/to/paper.pdf'),
    ('Supplementary.pdf', '/path/to/supp.pdf'),
], parentid='PARENTKEY')

# Upload files to existing attachment items
result = zot.upload_attachments(attachment_items, basedir='/path/to/files/')
# Existing entries need editable attachment dicts with key + version;
# filename resolves on disk relative to basedir. Do not set parentid for existing items.
if result['failure']:
    raise RuntimeError(result['failure'])

Upload result structure:

{
    'success': [attachment_item1, ...],
    'failure': [attachment_item2, ...],
    'unchanged': [attachment_item3, ...]
}
Raw lines 37 to 70
71## Attachment Templates
73```python
74# Get template for a file attachment
75template = zot.item_template('attachment', linkmode='imported_file')
76# linkmode options: 'imported_file', 'linked_file', 'imported_url', 'linked_url'
78# Available link modes
79modes = zot.item_attachment_link_modes()
80```

Attachment Templates

# Get template for a file attachment
template = zot.item_template('attachment', linkmode='imported_file')
# linkmode options: 'imported_file', 'linked_file', 'imported_url', 'linked_url'

# Available link modes
modes = zot.item_attachment_link_modes()
Raw lines 71 to 81
82## Downloading All PDFs from a Collection
84```python
85import os
87collection_key = 'COLKEY'
88output_dir = '/path/to/output/'
89os.makedirs(output_dir, exist_ok=True)
91items = zot.everything(zot.collection_items_top(collection_key))
92for item in items:
93 # A top-level item can itself be a standalone attachment.
94 children = ([item] if item['data']['itemType'] == 'attachment' else
95 zot.everything(zot.children(item['data']['key'])))
96 for child in children:
97 if child['data']['itemType'] == 'attachment' and \
98 child['data'].get('contentType') == 'application/pdf' and \
99 child['data'].get('linkMode') in {'imported_file', 'imported_url'}:
100 try:
101 # Key-based filenames prevent collisions between identically named PDFs.
102 zot.dump(child['key'], filename=f"{child['key']}.pdf", path=output_dir)
103 except Exception as e:
104 print(f"Failed to download {child['data']['key']}: {e}")
105```
107Upload results are distinct from `create_items()` results: lists under `success`, `failure`, and `unchanged`. Returned successful entries carry the current `version`; creation failures may include an `error` dict. The SDK manages file authorization, upload, and registration through `/items/{key}/file`, including MD5 preconditions and the storage URL returned by Zotero. A completed metadata create alone does not prove the file uploaded. See [official upload protocol](https://www.zotero.org/support/dev/web_api/v3/file_upload).

Downloading All PDFs from a Collection

import os

collection_key = 'COLKEY'
output_dir = '/path/to/output/'
os.makedirs(output_dir, exist_ok=True)

items = zot.everything(zot.collection_items_top(collection_key))
for item in items:
    # A top-level item can itself be a standalone attachment.
    children = ([item] if item['data']['itemType'] == 'attachment' else
                zot.everything(zot.children(item['data']['key'])))
    for child in children:
        if child['data']['itemType'] == 'attachment' and \
           child['data'].get('contentType') == 'application/pdf' and \
           child['data'].get('linkMode') in {'imported_file', 'imported_url'}:
            try:
                # Key-based filenames prevent collisions between identically named PDFs.
                zot.dump(child['key'], filename=f"{child['key']}.pdf", path=output_dir)
            except Exception as e:
                print(f"Failed to download {child['data']['key']}: {e}")

Upload results are distinct from create_items() results: lists under success, failure, and unchanged. Returned successful entries carry the current version; creation failures may include an error dict. The SDK manages file authorization, upload, and registration through /items/{key}/file, including MD5 preconditions and the storage URL returned by Zotero. A completed metadata create alone does not prove the file uploaded. See official upload protocol.

Raw lines 82 to 107