readwise-plus 0.1.0__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.
- readwise_plus-0.1.0/.github/workflows/ci.yml +48 -0
- readwise_plus-0.1.0/.gitignore +88 -0
- readwise_plus-0.1.0/Justfile +40 -0
- readwise_plus-0.1.0/PKG-INFO +113 -0
- readwise_plus-0.1.0/PLAN.md +342 -0
- readwise_plus-0.1.0/README.md +87 -0
- readwise_plus-0.1.0/llms-full.txt +865 -0
- readwise_plus-0.1.0/llms.txt +232 -0
- readwise_plus-0.1.0/pyproject.toml +81 -0
- readwise_plus-0.1.0/src/readwise_sdk/__init__.py +78 -0
- readwise_plus-0.1.0/src/readwise_sdk/cli/__init__.py +1 -0
- readwise_plus-0.1.0/src/readwise_sdk/cli/main.py +457 -0
- readwise_plus-0.1.0/src/readwise_sdk/client.py +404 -0
- readwise_plus-0.1.0/src/readwise_sdk/contrib/__init__.py +35 -0
- readwise_plus-0.1.0/src/readwise_sdk/contrib/batch_sync.py +335 -0
- readwise_plus-0.1.0/src/readwise_sdk/contrib/document_import.py +397 -0
- readwise_plus-0.1.0/src/readwise_sdk/contrib/highlight_push.py +271 -0
- readwise_plus-0.1.0/src/readwise_sdk/exceptions.py +76 -0
- readwise_plus-0.1.0/src/readwise_sdk/managers/__init__.py +14 -0
- readwise_plus-0.1.0/src/readwise_sdk/managers/books.py +198 -0
- readwise_plus-0.1.0/src/readwise_sdk/managers/documents.py +267 -0
- readwise_plus-0.1.0/src/readwise_sdk/managers/highlights.py +215 -0
- readwise_plus-0.1.0/src/readwise_sdk/managers/sync.py +243 -0
- readwise_plus-0.1.0/src/readwise_sdk/v2/__init__.py +21 -0
- readwise_plus-0.1.0/src/readwise_sdk/v2/client.py +395 -0
- readwise_plus-0.1.0/src/readwise_sdk/v2/models.py +247 -0
- readwise_plus-0.1.0/src/readwise_sdk/v3/__init__.py +21 -0
- readwise_plus-0.1.0/src/readwise_sdk/v3/client.py +311 -0
- readwise_plus-0.1.0/src/readwise_sdk/v3/models.py +257 -0
- readwise_plus-0.1.0/src/readwise_sdk/workflows/__init__.py +14 -0
- readwise_plus-0.1.0/src/readwise_sdk/workflows/digest.py +337 -0
- readwise_plus-0.1.0/src/readwise_sdk/workflows/inbox.py +385 -0
- readwise_plus-0.1.0/src/readwise_sdk/workflows/poller.py +306 -0
- readwise_plus-0.1.0/src/readwise_sdk/workflows/tags.py +320 -0
- readwise_plus-0.1.0/tests/__init__.py +1 -0
- readwise_plus-0.1.0/tests/conftest.py +24 -0
- readwise_plus-0.1.0/tests/managers/__init__.py +1 -0
- readwise_plus-0.1.0/tests/managers/test_books.py +141 -0
- readwise_plus-0.1.0/tests/managers/test_documents.py +160 -0
- readwise_plus-0.1.0/tests/managers/test_highlights.py +150 -0
- readwise_plus-0.1.0/tests/managers/test_sync.py +213 -0
- readwise_plus-0.1.0/tests/test_client.py +177 -0
- readwise_plus-0.1.0/tests/test_exceptions.py +80 -0
- readwise_plus-0.1.0/tests/test_live.py +355 -0
- readwise_plus-0.1.0/tests/v2/__init__.py +1 -0
- readwise_plus-0.1.0/tests/v2/test_client.py +371 -0
- readwise_plus-0.1.0/tests/v2/test_models.py +239 -0
- readwise_plus-0.1.0/tests/v3/__init__.py +1 -0
- readwise_plus-0.1.0/tests/v3/test_client.py +375 -0
- readwise_plus-0.1.0/tests/v3/test_models.py +174 -0
- readwise_plus-0.1.0/tests/workflows/__init__.py +1 -0
- readwise_plus-0.1.0/tests/workflows/test_digest.py +194 -0
- readwise_plus-0.1.0/tests/workflows/test_inbox.py +354 -0
- readwise_plus-0.1.0/tests/workflows/test_poller.py +222 -0
- readwise_plus-0.1.0/tests/workflows/test_tags.py +262 -0
- readwise_plus-0.1.0/uv.lock +526 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.12", "3.13"]
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v5
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: true
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
run: uv python install ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: uv sync --dev
|
|
28
|
+
|
|
29
|
+
- name: Install just
|
|
30
|
+
uses: taiki-e/install-action@v2
|
|
31
|
+
with:
|
|
32
|
+
tool: just
|
|
33
|
+
|
|
34
|
+
- name: Lint and type check
|
|
35
|
+
run: |
|
|
36
|
+
just lint
|
|
37
|
+
just format-check
|
|
38
|
+
just type
|
|
39
|
+
|
|
40
|
+
- name: Run tests with coverage
|
|
41
|
+
run: uv run pytest --cov=src/readwise_sdk --cov-report=xml --cov-report=term-missing -m "not live"
|
|
42
|
+
|
|
43
|
+
- name: Upload coverage to Codecov
|
|
44
|
+
if: matrix.python-version == '3.13'
|
|
45
|
+
uses: codecov/codecov-action@v5
|
|
46
|
+
with:
|
|
47
|
+
files: ./coverage.xml
|
|
48
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
|
|
27
|
+
# PyInstaller
|
|
28
|
+
*.manifest
|
|
29
|
+
*.spec
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# Unit test / coverage reports
|
|
36
|
+
htmlcov/
|
|
37
|
+
.tox/
|
|
38
|
+
.nox/
|
|
39
|
+
.coverage
|
|
40
|
+
.coverage.*
|
|
41
|
+
.cache
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
*.cover
|
|
45
|
+
*.py,cover
|
|
46
|
+
.hypothesis/
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
|
|
49
|
+
# Translations
|
|
50
|
+
*.mo
|
|
51
|
+
*.pot
|
|
52
|
+
|
|
53
|
+
# Environments
|
|
54
|
+
.env
|
|
55
|
+
.venv
|
|
56
|
+
env/
|
|
57
|
+
venv/
|
|
58
|
+
ENV/
|
|
59
|
+
env.bak/
|
|
60
|
+
venv.bak/
|
|
61
|
+
|
|
62
|
+
# IDEs
|
|
63
|
+
.idea/
|
|
64
|
+
.vscode/
|
|
65
|
+
*.swp
|
|
66
|
+
*.swo
|
|
67
|
+
*~
|
|
68
|
+
|
|
69
|
+
# mypy / ty
|
|
70
|
+
.mypy_cache/
|
|
71
|
+
.dmypy.json
|
|
72
|
+
dmypy.json
|
|
73
|
+
.ty_cache/
|
|
74
|
+
|
|
75
|
+
# ruff
|
|
76
|
+
.ruff_cache/
|
|
77
|
+
|
|
78
|
+
# uv
|
|
79
|
+
# uv.lock is committed for reproducible builds
|
|
80
|
+
|
|
81
|
+
# OS
|
|
82
|
+
.DS_Store
|
|
83
|
+
Thumbs.db
|
|
84
|
+
|
|
85
|
+
# Project specific
|
|
86
|
+
*.db
|
|
87
|
+
*.sqlite
|
|
88
|
+
.readwise_state.json
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
set shell := ["bash", "-cu"]
|
|
2
|
+
|
|
3
|
+
default:
|
|
4
|
+
@just --list
|
|
5
|
+
|
|
6
|
+
fmt:
|
|
7
|
+
uv run ruff format .
|
|
8
|
+
|
|
9
|
+
format-check:
|
|
10
|
+
uv run ruff format --check .
|
|
11
|
+
|
|
12
|
+
lint:
|
|
13
|
+
uv run ruff check .
|
|
14
|
+
|
|
15
|
+
lint-fix:
|
|
16
|
+
uv run ruff check . --fix
|
|
17
|
+
|
|
18
|
+
type:
|
|
19
|
+
uv run ty check . --exclude "src/readwise_sdk/cli/"
|
|
20
|
+
|
|
21
|
+
test:
|
|
22
|
+
uv run pytest
|
|
23
|
+
|
|
24
|
+
test-live:
|
|
25
|
+
uv run pytest -m live
|
|
26
|
+
|
|
27
|
+
test-cov:
|
|
28
|
+
uv run pytest --cov=src/readwise_sdk --cov-report=term-missing
|
|
29
|
+
|
|
30
|
+
# FIX + CHECK: Run before every commit
|
|
31
|
+
fc: fmt lint-fix lint type test
|
|
32
|
+
|
|
33
|
+
ci: lint format-check type test
|
|
34
|
+
|
|
35
|
+
install:
|
|
36
|
+
uv sync --dev
|
|
37
|
+
|
|
38
|
+
# Install with CLI extras
|
|
39
|
+
install-cli:
|
|
40
|
+
uv sync --dev --extra cli
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: readwise-plus
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Comprehensive Python SDK for Readwise with high-level workflow abstractions. Supports V2 (highlights/books) and V3 (Reader) APIs with managers, workflows, and CLI.
|
|
5
|
+
Project-URL: Homepage, https://github.com/EvanOman/readwise-sdk
|
|
6
|
+
Project-URL: Repository, https://github.com/EvanOman/readwise-sdk
|
|
7
|
+
Project-URL: Issues, https://github.com/EvanOman/readwise-sdk/issues
|
|
8
|
+
Author: Evan Oman
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: api,digest,highlights,reader,readwise,sdk,workflows
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: httpx>=0.27.0
|
|
21
|
+
Requires-Dist: pydantic>=2.0.0
|
|
22
|
+
Provides-Extra: cli
|
|
23
|
+
Requires-Dist: rich>=14.0.0; extra == 'cli'
|
|
24
|
+
Requires-Dist: typer>=0.21.0; extra == 'cli'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# readwise-sdk
|
|
28
|
+
|
|
29
|
+
[](https://github.com/EvanOman/readwise-sdk/actions/workflows/ci.yml)
|
|
30
|
+
[](https://codecov.io/gh/EvanOman/readwise-sdk)
|
|
31
|
+
|
|
32
|
+
Comprehensive Python SDK for [Readwise](https://readwise.io) with high-level workflow abstractions.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Core Layer**: Direct Python methods for each Readwise API endpoint
|
|
37
|
+
- Readwise API v2 (highlights, books, tags, daily review)
|
|
38
|
+
- Reader API v3 (documents, reading list)
|
|
39
|
+
- **Abstraction Layer**: User-friendly, workflow-oriented operations
|
|
40
|
+
- Highlight and book management
|
|
41
|
+
- Document inbox handling
|
|
42
|
+
- Digest creation and export
|
|
43
|
+
- Background sync and polling
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install readwise-sdk
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
With CLI support:
|
|
52
|
+
```bash
|
|
53
|
+
pip install readwise-sdk[cli]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from readwise_sdk import ReadwiseClient
|
|
60
|
+
|
|
61
|
+
# Initialize with your API token
|
|
62
|
+
client = ReadwiseClient(api_key="your_token_here")
|
|
63
|
+
|
|
64
|
+
# Or use environment variable READWISE_API_KEY
|
|
65
|
+
client = ReadwiseClient()
|
|
66
|
+
|
|
67
|
+
# Validate your token
|
|
68
|
+
client.validate_token()
|
|
69
|
+
|
|
70
|
+
# Get all highlights
|
|
71
|
+
for highlight in client.v2.highlights.list():
|
|
72
|
+
print(highlight.text)
|
|
73
|
+
|
|
74
|
+
# Get Reader inbox
|
|
75
|
+
for doc in client.v3.documents.list(location="new"):
|
|
76
|
+
print(doc.title)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## High-Level Abstractions
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from readwise_sdk import ReadwiseClient
|
|
83
|
+
from readwise_sdk.managers import HighlightManager, DocumentManager
|
|
84
|
+
|
|
85
|
+
client = ReadwiseClient()
|
|
86
|
+
|
|
87
|
+
# Highlight workflows
|
|
88
|
+
highlights = HighlightManager(client)
|
|
89
|
+
recent = highlights.get_highlights_since(days=7)
|
|
90
|
+
highlights.bulk_tag(highlight_ids, "to-review")
|
|
91
|
+
|
|
92
|
+
# Document workflows
|
|
93
|
+
docs = DocumentManager(client)
|
|
94
|
+
inbox = docs.get_inbox()
|
|
95
|
+
docs.archive(doc_id)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Development
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Install dependencies
|
|
102
|
+
just install
|
|
103
|
+
|
|
104
|
+
# Run all checks (format, lint, type-check, test)
|
|
105
|
+
just fc
|
|
106
|
+
|
|
107
|
+
# Run tests only
|
|
108
|
+
just test
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Readwise SDK - Project Plan
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
A comprehensive Python SDK for the Readwise platform providing:
|
|
6
|
+
1. **Core Layer**: Direct Python methods for each API endpoint (v2 + v3)
|
|
7
|
+
2. **Abstraction Layer**: User-friendly, workflow-oriented operations for power readers
|
|
8
|
+
|
|
9
|
+
## Research Summary
|
|
10
|
+
|
|
11
|
+
### API Capabilities
|
|
12
|
+
|
|
13
|
+
**Readwise API v2** (Highlights & Books):
|
|
14
|
+
- `GET/POST/PATCH/DELETE /api/v2/highlights/` - Highlight CRUD
|
|
15
|
+
- `GET /api/v2/books/` - Book listing with filtering
|
|
16
|
+
- `GET/POST/PATCH/DELETE /api/v2/highlights/{id}/tags/` - Tag management
|
|
17
|
+
- `GET /api/v2/export/` - Bulk export with pagination
|
|
18
|
+
- `GET /api/v2/review/` - Daily review highlights
|
|
19
|
+
- `GET /api/v2/auth/` - Token validation
|
|
20
|
+
|
|
21
|
+
**Readwise Reader API v3** (Documents):
|
|
22
|
+
- `POST /api/v3/save/` - Create documents
|
|
23
|
+
- `GET /api/v3/list/` - List documents with filtering
|
|
24
|
+
- `PATCH /api/v3/update/{id}/` - Update document metadata
|
|
25
|
+
- `DELETE /api/v3/delete/{id}/` - Delete documents
|
|
26
|
+
- `GET /api/v3/tags/` - List all tags
|
|
27
|
+
|
|
28
|
+
### Rate Limits
|
|
29
|
+
- Base: 240 requests/minute
|
|
30
|
+
- Highlight/Book LIST: 20 requests/minute
|
|
31
|
+
- Reader operations: 50 requests/minute
|
|
32
|
+
|
|
33
|
+
### Patterns from Existing Projects
|
|
34
|
+
|
|
35
|
+
From `readwise_digest`:
|
|
36
|
+
- Iterator-based pagination
|
|
37
|
+
- Comprehensive error hierarchy
|
|
38
|
+
- Retry with exponential backoff
|
|
39
|
+
- State persistence for polling
|
|
40
|
+
|
|
41
|
+
From `highlight_helper`:
|
|
42
|
+
- Async HTTP client (httpx)
|
|
43
|
+
- Background sync workflows
|
|
44
|
+
- Batch operations with result tracking
|
|
45
|
+
- Field truncation handling
|
|
46
|
+
|
|
47
|
+
From `sane_reader`:
|
|
48
|
+
- Document location/category filtering
|
|
49
|
+
- HTML content extraction
|
|
50
|
+
- Tag-based workflows
|
|
51
|
+
- Incremental sync patterns
|
|
52
|
+
|
|
53
|
+
From `goodreads_api`:
|
|
54
|
+
- Pydantic models with field aliases
|
|
55
|
+
- Rate-limiting HTTP client wrapper
|
|
56
|
+
- CLI with typer
|
|
57
|
+
- Browser cookie extraction
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Milestones
|
|
62
|
+
|
|
63
|
+
### Milestone 1: Core SDK Foundation
|
|
64
|
+
**Goal**: Establish project structure with proper tooling and base HTTP client
|
|
65
|
+
|
|
66
|
+
**Deliverables**:
|
|
67
|
+
1. Project scaffolding (pyproject.toml, Justfile, CI)
|
|
68
|
+
2. Base HTTP client with:
|
|
69
|
+
- Token authentication
|
|
70
|
+
- Rate limiting (configurable)
|
|
71
|
+
- Retry with exponential backoff
|
|
72
|
+
- Timeout handling
|
|
73
|
+
3. Exception hierarchy:
|
|
74
|
+
- `ReadwiseError` (base)
|
|
75
|
+
- `AuthenticationError` (401)
|
|
76
|
+
- `RateLimitError` (429, with retry_after)
|
|
77
|
+
- `NotFoundError` (404)
|
|
78
|
+
- `ValidationError` (400)
|
|
79
|
+
- `ServerError` (5xx)
|
|
80
|
+
4. Sync and async client variants
|
|
81
|
+
5. Unit tests for HTTP client and error handling
|
|
82
|
+
|
|
83
|
+
**Testing**:
|
|
84
|
+
- Unit tests with mocked HTTP responses
|
|
85
|
+
- Test error handling for all status codes
|
|
86
|
+
- Test retry logic
|
|
87
|
+
- `just fc` passes
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### Milestone 2: Readwise API v2 Client
|
|
92
|
+
**Goal**: Complete implementation of all Readwise API v2 endpoints
|
|
93
|
+
|
|
94
|
+
**Deliverables**:
|
|
95
|
+
1. Pydantic models:
|
|
96
|
+
- `Book`, `Highlight`, `Tag`, `DailyReview`
|
|
97
|
+
- Request/response models with validation
|
|
98
|
+
2. Highlight operations:
|
|
99
|
+
- `list_highlights(filters)` - with pagination iterator
|
|
100
|
+
- `get_highlight(id)`
|
|
101
|
+
- `create_highlights(highlights)` - batch create
|
|
102
|
+
- `update_highlight(id, fields)`
|
|
103
|
+
- `delete_highlight(id)`
|
|
104
|
+
3. Book operations:
|
|
105
|
+
- `list_books(filters)` - with pagination iterator
|
|
106
|
+
- `get_book(id)`
|
|
107
|
+
4. Tag operations:
|
|
108
|
+
- `list_highlight_tags(highlight_id)`
|
|
109
|
+
- `create_highlight_tag(highlight_id, name)`
|
|
110
|
+
- `update_highlight_tag(highlight_id, tag_id, name)`
|
|
111
|
+
- `delete_highlight_tag(highlight_id, tag_id)`
|
|
112
|
+
- Book tag operations (same pattern)
|
|
113
|
+
5. Export operation:
|
|
114
|
+
- `export_highlights(filters)` - cursor-based pagination
|
|
115
|
+
6. Daily review:
|
|
116
|
+
- `get_daily_review()`
|
|
117
|
+
7. Auth:
|
|
118
|
+
- `validate_token()`
|
|
119
|
+
|
|
120
|
+
**Testing**:
|
|
121
|
+
- Unit tests with fixtures for each endpoint
|
|
122
|
+
- Integration tests (marked, require API key)
|
|
123
|
+
- Test pagination exhaustion
|
|
124
|
+
- Test filter combinations
|
|
125
|
+
- `just fc` passes
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### Milestone 3: Reader API v3 Client
|
|
130
|
+
**Goal**: Complete implementation of all Readwise Reader API v3 endpoints
|
|
131
|
+
|
|
132
|
+
**Deliverables**:
|
|
133
|
+
1. Pydantic models:
|
|
134
|
+
- `Document` with all fields
|
|
135
|
+
- `DocumentLocation` enum (new, later, archive, feed)
|
|
136
|
+
- `DocumentCategory` enum (article, email, pdf, etc.)
|
|
137
|
+
2. Document operations:
|
|
138
|
+
- `create_document(url, **kwargs)` - with all optional fields
|
|
139
|
+
- `list_documents(filters)` - with pagination iterator
|
|
140
|
+
- `get_document(id, with_content=False)`
|
|
141
|
+
- `update_document(id, fields)`
|
|
142
|
+
- `delete_document(id)`
|
|
143
|
+
3. Tag operations:
|
|
144
|
+
- `list_tags()` - with pagination
|
|
145
|
+
4. Content handling:
|
|
146
|
+
- Option to fetch HTML content
|
|
147
|
+
- HTML to text extraction utilities
|
|
148
|
+
|
|
149
|
+
**Testing**:
|
|
150
|
+
- Unit tests with fixtures
|
|
151
|
+
- Integration tests (marked)
|
|
152
|
+
- Test document creation with various content types
|
|
153
|
+
- Test filtering by location/category
|
|
154
|
+
- `just fc` passes
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### Milestone 4: High-Level Abstractions
|
|
159
|
+
**Goal**: User-friendly operations built on top of core client
|
|
160
|
+
|
|
161
|
+
**Deliverables**:
|
|
162
|
+
1. `HighlightManager`:
|
|
163
|
+
- `get_all_highlights()` - exhaust pagination automatically
|
|
164
|
+
- `get_highlights_since(datetime)` - incremental fetch
|
|
165
|
+
- `get_highlights_by_book(book_id)`
|
|
166
|
+
- `get_highlights_with_notes()` - filter annotated
|
|
167
|
+
- `search_highlights(query)` - text search across highlights
|
|
168
|
+
- `bulk_tag(highlight_ids, tag)` - batch tagging
|
|
169
|
+
- `bulk_untag(highlight_ids, tag)` - batch untagging
|
|
170
|
+
|
|
171
|
+
2. `BookManager`:
|
|
172
|
+
- `get_all_books()`
|
|
173
|
+
- `get_books_by_category(category)`
|
|
174
|
+
- `get_book_with_highlights(book_id)` - enriched response
|
|
175
|
+
- `get_reading_stats()` - aggregated statistics
|
|
176
|
+
|
|
177
|
+
3. `DocumentManager` (Reader):
|
|
178
|
+
- `get_inbox()` - documents in "new" location
|
|
179
|
+
- `get_reading_list()` - documents in "later"
|
|
180
|
+
- `get_archive()` - archived documents
|
|
181
|
+
- `move_to_later(doc_id)` / `archive(doc_id)`
|
|
182
|
+
- `bulk_tag_documents(doc_ids, tags)`
|
|
183
|
+
- `get_documents_since(datetime)`
|
|
184
|
+
|
|
185
|
+
4. `SyncManager`:
|
|
186
|
+
- `full_sync()` - fetch everything
|
|
187
|
+
- `incremental_sync(since)` - fetch updates only
|
|
188
|
+
- State persistence (configurable backend)
|
|
189
|
+
- Callback hooks for new items
|
|
190
|
+
|
|
191
|
+
**Testing**:
|
|
192
|
+
- Unit tests for each manager
|
|
193
|
+
- Test batch operations
|
|
194
|
+
- Test sync state persistence
|
|
195
|
+
- `just fc` passes
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### Milestone 5: Advanced Workflows
|
|
200
|
+
**Goal**: Power-user workflows based on observed usage patterns
|
|
201
|
+
|
|
202
|
+
**Deliverables**:
|
|
203
|
+
1. `DigestBuilder`:
|
|
204
|
+
- `create_daily_digest()` - highlights from last 24h
|
|
205
|
+
- `create_weekly_digest()` - highlights from last 7d
|
|
206
|
+
- `create_book_digest(book_id)` - all highlights for a book
|
|
207
|
+
- Export formats: Markdown, JSON, CSV, plain text
|
|
208
|
+
- Grouping options: by book, by date, by source
|
|
209
|
+
|
|
210
|
+
2. `BackgroundPoller`:
|
|
211
|
+
- Configurable polling interval
|
|
212
|
+
- Graceful shutdown (signal handling)
|
|
213
|
+
- Error recovery with backoff
|
|
214
|
+
- State persistence across restarts
|
|
215
|
+
- Callback system for new highlights/documents
|
|
216
|
+
|
|
217
|
+
3. `TagWorkflow`:
|
|
218
|
+
- `auto_tag_by_content(patterns)` - regex-based tagging
|
|
219
|
+
- `tag_cleanup()` - find/merge duplicate tags
|
|
220
|
+
- `tag_report()` - usage statistics
|
|
221
|
+
|
|
222
|
+
4. `ReadingInbox`:
|
|
223
|
+
- `triage()` - interactive inbox processing helper
|
|
224
|
+
- `smart_archive(rules)` - auto-archive based on rules
|
|
225
|
+
- `reading_queue_stats()` - queue depth, age distribution
|
|
226
|
+
|
|
227
|
+
5. CLI (optional but recommended):
|
|
228
|
+
- `readwise highlights list/create/export`
|
|
229
|
+
- `readwise books list/show`
|
|
230
|
+
- `readwise reader inbox/archive/save`
|
|
231
|
+
- `readwise sync --incremental`
|
|
232
|
+
- `readwise digest --format markdown`
|
|
233
|
+
|
|
234
|
+
**Testing**:
|
|
235
|
+
- Unit tests for workflows
|
|
236
|
+
- Integration tests for CLI commands
|
|
237
|
+
- Test background poller lifecycle
|
|
238
|
+
- `just fc` passes
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Technical Standards
|
|
243
|
+
|
|
244
|
+
### Python Practices (from pystd)
|
|
245
|
+
- Python 3.12+
|
|
246
|
+
- uv for package management
|
|
247
|
+
- ruff for linting/formatting
|
|
248
|
+
- ty for type checking
|
|
249
|
+
- just for task running
|
|
250
|
+
- pytest for testing
|
|
251
|
+
- GitHub Actions CI
|
|
252
|
+
|
|
253
|
+
### Dependencies
|
|
254
|
+
```toml
|
|
255
|
+
dependencies = [
|
|
256
|
+
"httpx>=0.27.0",
|
|
257
|
+
"pydantic>=2.0.0",
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
[dependency-groups]
|
|
261
|
+
dev = [
|
|
262
|
+
"pytest>=9.0.0",
|
|
263
|
+
"pytest-cov>=6.0.0",
|
|
264
|
+
"pytest-asyncio>=0.24.0",
|
|
265
|
+
"respx>=0.22.0", # httpx mocking
|
|
266
|
+
"ruff>=0.14.0",
|
|
267
|
+
"ty>=0.0.8",
|
|
268
|
+
]
|
|
269
|
+
cli = [
|
|
270
|
+
"typer>=0.21.0",
|
|
271
|
+
"rich>=14.0.0",
|
|
272
|
+
]
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Project Structure
|
|
276
|
+
```
|
|
277
|
+
readwise-sdk/
|
|
278
|
+
├── src/
|
|
279
|
+
│ └── readwise_sdk/
|
|
280
|
+
│ ├── __init__.py
|
|
281
|
+
│ ├── client.py # Base HTTP client
|
|
282
|
+
│ ├── exceptions.py # Error hierarchy
|
|
283
|
+
│ ├── v2/ # Readwise API v2
|
|
284
|
+
│ │ ├── __init__.py
|
|
285
|
+
│ │ ├── client.py
|
|
286
|
+
│ │ ├── models.py
|
|
287
|
+
│ │ ├── highlights.py
|
|
288
|
+
│ │ ├── books.py
|
|
289
|
+
│ │ └── tags.py
|
|
290
|
+
│ ├── v3/ # Reader API v3
|
|
291
|
+
│ │ ├── __init__.py
|
|
292
|
+
│ │ ├── client.py
|
|
293
|
+
│ │ ├── models.py
|
|
294
|
+
│ │ └── documents.py
|
|
295
|
+
│ ├── managers/ # High-level abstractions
|
|
296
|
+
│ │ ├── __init__.py
|
|
297
|
+
│ │ ├── highlights.py
|
|
298
|
+
│ │ ├── books.py
|
|
299
|
+
│ │ ├── documents.py
|
|
300
|
+
│ │ └── sync.py
|
|
301
|
+
│ ├── workflows/ # Advanced workflows
|
|
302
|
+
│ │ ├── __init__.py
|
|
303
|
+
│ │ ├── digest.py
|
|
304
|
+
│ │ ├── poller.py
|
|
305
|
+
│ │ ├── tags.py
|
|
306
|
+
│ │ └── inbox.py
|
|
307
|
+
│ └── cli/ # CLI (optional)
|
|
308
|
+
│ ├── __init__.py
|
|
309
|
+
│ └── main.py
|
|
310
|
+
├── tests/
|
|
311
|
+
│ ├── conftest.py
|
|
312
|
+
│ ├── fixtures/
|
|
313
|
+
│ ├── test_client.py
|
|
314
|
+
│ ├── v2/
|
|
315
|
+
│ ├── v3/
|
|
316
|
+
│ ├── managers/
|
|
317
|
+
│ └── workflows/
|
|
318
|
+
├── pyproject.toml
|
|
319
|
+
├── Justfile
|
|
320
|
+
├── README.md
|
|
321
|
+
└── .github/
|
|
322
|
+
└── workflows/
|
|
323
|
+
└── ci.yml
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Success Criteria
|
|
329
|
+
|
|
330
|
+
Each milestone is complete when:
|
|
331
|
+
1. All deliverables implemented
|
|
332
|
+
2. Unit tests pass with >80% coverage
|
|
333
|
+
3. Integration tests pass (when applicable)
|
|
334
|
+
4. `just fc` passes (format, lint, type-check, test)
|
|
335
|
+
5. Documentation updated
|
|
336
|
+
6. GitHub issue closed
|
|
337
|
+
|
|
338
|
+
## Next Steps
|
|
339
|
+
|
|
340
|
+
1. Initialize GitHub repository
|
|
341
|
+
2. Create GitHub issues for each milestone
|
|
342
|
+
3. Begin Milestone 1 implementation
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# readwise-sdk
|
|
2
|
+
|
|
3
|
+
[](https://github.com/EvanOman/readwise-sdk/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/EvanOman/readwise-sdk)
|
|
5
|
+
|
|
6
|
+
Comprehensive Python SDK for [Readwise](https://readwise.io) with high-level workflow abstractions.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Core Layer**: Direct Python methods for each Readwise API endpoint
|
|
11
|
+
- Readwise API v2 (highlights, books, tags, daily review)
|
|
12
|
+
- Reader API v3 (documents, reading list)
|
|
13
|
+
- **Abstraction Layer**: User-friendly, workflow-oriented operations
|
|
14
|
+
- Highlight and book management
|
|
15
|
+
- Document inbox handling
|
|
16
|
+
- Digest creation and export
|
|
17
|
+
- Background sync and polling
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install readwise-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
With CLI support:
|
|
26
|
+
```bash
|
|
27
|
+
pip install readwise-sdk[cli]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from readwise_sdk import ReadwiseClient
|
|
34
|
+
|
|
35
|
+
# Initialize with your API token
|
|
36
|
+
client = ReadwiseClient(api_key="your_token_here")
|
|
37
|
+
|
|
38
|
+
# Or use environment variable READWISE_API_KEY
|
|
39
|
+
client = ReadwiseClient()
|
|
40
|
+
|
|
41
|
+
# Validate your token
|
|
42
|
+
client.validate_token()
|
|
43
|
+
|
|
44
|
+
# Get all highlights
|
|
45
|
+
for highlight in client.v2.highlights.list():
|
|
46
|
+
print(highlight.text)
|
|
47
|
+
|
|
48
|
+
# Get Reader inbox
|
|
49
|
+
for doc in client.v3.documents.list(location="new"):
|
|
50
|
+
print(doc.title)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## High-Level Abstractions
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from readwise_sdk import ReadwiseClient
|
|
57
|
+
from readwise_sdk.managers import HighlightManager, DocumentManager
|
|
58
|
+
|
|
59
|
+
client = ReadwiseClient()
|
|
60
|
+
|
|
61
|
+
# Highlight workflows
|
|
62
|
+
highlights = HighlightManager(client)
|
|
63
|
+
recent = highlights.get_highlights_since(days=7)
|
|
64
|
+
highlights.bulk_tag(highlight_ids, "to-review")
|
|
65
|
+
|
|
66
|
+
# Document workflows
|
|
67
|
+
docs = DocumentManager(client)
|
|
68
|
+
inbox = docs.get_inbox()
|
|
69
|
+
docs.archive(doc_id)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Development
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Install dependencies
|
|
76
|
+
just install
|
|
77
|
+
|
|
78
|
+
# Run all checks (format, lint, type-check, test)
|
|
79
|
+
just fc
|
|
80
|
+
|
|
81
|
+
# Run tests only
|
|
82
|
+
just test
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|