easypaperless 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.
Files changed (90) hide show
  1. easypaperless-0.1.0/.env.EXAMPLE +5 -0
  2. easypaperless-0.1.0/.github/workflows/publish.yml +31 -0
  3. easypaperless-0.1.0/.github/workflows/publish_testpypi.yml +25 -0
  4. easypaperless-0.1.0/.gitignore +42 -0
  5. easypaperless-0.1.0/CHANGELOG.md +6 -0
  6. easypaperless-0.1.0/CLAUDE.md +121 -0
  7. easypaperless-0.1.0/LICENSE +21 -0
  8. easypaperless-0.1.0/PKG-INFO +212 -0
  9. easypaperless-0.1.0/README.md +178 -0
  10. easypaperless-0.1.0/docs/PRD.md +46 -0
  11. easypaperless-0.1.0/docs/api-conventions.md +79 -0
  12. easypaperless-0.1.0/docs/easypaperless.html +8953 -0
  13. easypaperless-0.1.0/docs/index.html +7 -0
  14. easypaperless-0.1.0/docs/search.js +46 -0
  15. easypaperless-0.1.0/features/INDEX.md +23 -0
  16. easypaperless-0.1.0/features/PROJ-1-http-client-core.md +149 -0
  17. easypaperless-0.1.0/features/PROJ-10-tags-crud.md +157 -0
  18. easypaperless-0.1.0/features/PROJ-11-correspondents-crud.md +128 -0
  19. easypaperless-0.1.0/features/PROJ-12-document-types-crud.md +149 -0
  20. easypaperless-0.1.0/features/PROJ-13-custom-fields-crud.md +150 -0
  21. easypaperless-0.1.0/features/PROJ-14-storage-paths-crud.md +134 -0
  22. easypaperless-0.1.0/features/PROJ-15-non-document-bulk-operations.md +120 -0
  23. easypaperless-0.1.0/features/PROJ-16-sync-client.md +100 -0
  24. easypaperless-0.1.0/features/PROJ-17-document-notes.md +123 -0
  25. easypaperless-0.1.0/features/PROJ-2-name-to-id-resolver.md +153 -0
  26. easypaperless-0.1.0/features/PROJ-3-list-documents.md +305 -0
  27. easypaperless-0.1.0/features/PROJ-4-get-document.md +111 -0
  28. easypaperless-0.1.0/features/PROJ-5-update-document.md +114 -0
  29. easypaperless-0.1.0/features/PROJ-6-delete-document.md +82 -0
  30. easypaperless-0.1.0/features/PROJ-7-download-document.md +95 -0
  31. easypaperless-0.1.0/features/PROJ-8-upload-document.md +127 -0
  32. easypaperless-0.1.0/features/PROJ-9-document-bulk-operations.md +147 -0
  33. easypaperless-0.1.0/pyproject.toml +67 -0
  34. easypaperless-0.1.0/scripts/cli.py +1732 -0
  35. easypaperless-0.1.0/src/easypaperless/__init__.py +72 -0
  36. easypaperless-0.1.0/src/easypaperless/_internal/__init__.py +0 -0
  37. easypaperless-0.1.0/src/easypaperless/_internal/http.py +205 -0
  38. easypaperless-0.1.0/src/easypaperless/_internal/mixins/__init__.py +25 -0
  39. easypaperless-0.1.0/src/easypaperless/_internal/mixins/correspondents.py +196 -0
  40. easypaperless-0.1.0/src/easypaperless/_internal/mixins/custom_fields.py +179 -0
  41. easypaperless-0.1.0/src/easypaperless/_internal/mixins/document_bulk.py +175 -0
  42. easypaperless-0.1.0/src/easypaperless/_internal/mixins/document_types.py +198 -0
  43. easypaperless-0.1.0/src/easypaperless/_internal/mixins/documents.py +516 -0
  44. easypaperless-0.1.0/src/easypaperless/_internal/mixins/non_document_bulk.py +176 -0
  45. easypaperless-0.1.0/src/easypaperless/_internal/mixins/notes.py +76 -0
  46. easypaperless-0.1.0/src/easypaperless/_internal/mixins/storage_paths.py +210 -0
  47. easypaperless-0.1.0/src/easypaperless/_internal/mixins/tags.py +214 -0
  48. easypaperless-0.1.0/src/easypaperless/_internal/mixins/upload.py +149 -0
  49. easypaperless-0.1.0/src/easypaperless/_internal/resolvers.py +63 -0
  50. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/__init__.py +25 -0
  51. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/correspondents.py +85 -0
  52. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/custom_fields.py +70 -0
  53. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/document_bulk.py +94 -0
  54. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/document_types.py +85 -0
  55. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/documents.py +154 -0
  56. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/non_document_bulk.py +103 -0
  57. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/notes.py +29 -0
  58. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/storage_paths.py +89 -0
  59. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/tags.py +97 -0
  60. easypaperless-0.1.0/src/easypaperless/_internal/sync_mixins/upload.py +50 -0
  61. easypaperless-0.1.0/src/easypaperless/client.py +234 -0
  62. easypaperless-0.1.0/src/easypaperless/exceptions.py +63 -0
  63. easypaperless-0.1.0/src/easypaperless/models/__init__.py +39 -0
  64. easypaperless-0.1.0/src/easypaperless/models/_base.py +17 -0
  65. easypaperless-0.1.0/src/easypaperless/models/correspondents.py +34 -0
  66. easypaperless-0.1.0/src/easypaperless/models/custom_fields.py +44 -0
  67. easypaperless-0.1.0/src/easypaperless/models/document_types.py +29 -0
  68. easypaperless-0.1.0/src/easypaperless/models/documents.py +217 -0
  69. easypaperless-0.1.0/src/easypaperless/models/permissions.py +13 -0
  70. easypaperless-0.1.0/src/easypaperless/models/storage_paths.py +32 -0
  71. easypaperless-0.1.0/src/easypaperless/models/tags.py +39 -0
  72. easypaperless-0.1.0/src/easypaperless/sync.py +187 -0
  73. easypaperless-0.1.0/tests/__init__.py +0 -0
  74. easypaperless-0.1.0/tests/conftest.py +27 -0
  75. easypaperless-0.1.0/tests/integration/__init__.py +0 -0
  76. easypaperless-0.1.0/tests/integration/conftest.py +43 -0
  77. easypaperless-0.1.0/tests/integration/test_documents.py +482 -0
  78. easypaperless-0.1.0/tests/integration/test_notes.py +29 -0
  79. easypaperless-0.1.0/tests/integration/test_resources.py +87 -0
  80. easypaperless-0.1.0/tests/integration/test_upload.py +57 -0
  81. easypaperless-0.1.0/tests/test_client_bulk.py +304 -0
  82. easypaperless-0.1.0/tests/test_client_documents.py +1175 -0
  83. easypaperless-0.1.0/tests/test_client_notes.py +107 -0
  84. easypaperless-0.1.0/tests/test_client_tags.py +1211 -0
  85. easypaperless-0.1.0/tests/test_client_upload.py +311 -0
  86. easypaperless-0.1.0/tests/test_exceptions.py +50 -0
  87. easypaperless-0.1.0/tests/test_http.py +481 -0
  88. easypaperless-0.1.0/tests/test_models.py +129 -0
  89. easypaperless-0.1.0/tests/test_resolvers.py +98 -0
  90. easypaperless-0.1.0/tests/test_sync.py +666 -0
@@ -0,0 +1,5 @@
1
+ # Copy this file to .env and fill in your credentials.
2
+ # .env is git-ignored and will never be committed.
3
+
4
+ PAPERLESS_URL=https://your-paperless-instance.example.com
5
+ PAPERLESS_API_KEY=your_api_key_here
@@ -0,0 +1,31 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ name: Build and publish Python package
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout repository
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.11"
21
+
22
+ - name: Install build backend
23
+ run: pip install build
24
+
25
+ - name: Build package
26
+ run: python -m build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1
30
+ with:
31
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,25 @@
1
+ name: Publish to TestPyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*-rc*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.11"
18
+
19
+ - run: pip install build
20
+ - run: python -m build
21
+
22
+ - uses: pypa/gh-action-pypi-publish@release/v1
23
+ with:
24
+ repository-url: https://test.pypi.org/legacy/
25
+ password: ${{ secrets.TEST_PYPI_API_TOKEN }}
@@ -0,0 +1,42 @@
1
+ # Virtual environment
2
+ venv/
3
+ .venv/
4
+
5
+ # Environment variables
6
+ .env
7
+ .env.*
8
+ !.env.EXAMPLE
9
+
10
+ # Python
11
+ __pycache__/
12
+ *.py[cod]
13
+ *.pyo
14
+ *.pyd
15
+ *.egg-info/
16
+ dist/
17
+ build/
18
+ *.egg
19
+
20
+ # Test & coverage
21
+ .pytest_cache/
22
+ .coverage
23
+ htmlcov/
24
+
25
+ # IDE
26
+ .vscode/
27
+ .idea/
28
+ *.iml
29
+
30
+ # Claude Code
31
+ .claude/
32
+
33
+ # OS
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # Deleted/archived code
38
+ _deleted/
39
+
40
+ # Local SQLite store
41
+ *.db
42
+ *.sqlite
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [Unreleased]
@@ -0,0 +1,121 @@
1
+ # Paperless API Wrapper Project
2
+ > A Python project template with an AI-powered development workflow using specialized skills for Requirements, Architecture, API Design, Development, QA, and Deployment.
3
+
4
+ ## Tech Stack
5
+ - **Language:** Python 3.11+
6
+ - **HTTP client:** `httpx` (async-first)
7
+ - **Data models:** Pydantic v2
8
+ - **Build:** Hatch + hatchling
9
+ - **Linting/formatting:** Ruff
10
+ - **Type checking:** Mypy (strict)
11
+ - **Testing:** pytest + pytest-asyncio + respx
12
+
13
+ ## Project Structure
14
+ ```
15
+ src/
16
+ └── easypaperless/
17
+ ├── __init__.py # public API: PaperlessClient, SyncPaperlessClient
18
+ ├── client.py # async PaperlessClient (composes from async mixins)
19
+ ├── sync.py # SyncPaperlessClient (composes from sync mixins)
20
+ ├── exceptions.py # custom exception hierarchy
21
+ ├── models/
22
+ │ ├── __init__.py
23
+ │ ├── documents.py
24
+ │ ├── tags.py
25
+ │ ├── correspondents.py
26
+ │ ├── document_types.py
27
+ │ ├── storage_paths.py
28
+ │ ├── custom_fields.py
29
+ │ └── permissions.py
30
+ └── _internal/
31
+ ├── http.py # httpx session, auth, request helpers
32
+ ├── resolvers.py # name-to-ID resolution and caching
33
+ ├── mixins/ # one async mixin per resource group
34
+ │ ├── __init__.py
35
+ │ ├── documents.py
36
+ │ ├── notes.py
37
+ │ ├── upload.py
38
+ │ ├── document_bulk.py
39
+ │ ├── non_document_bulk.py
40
+ │ ├── tags.py
41
+ │ ├── correspondents.py
42
+ │ ├── document_types.py
43
+ │ ├── storage_paths.py
44
+ │ └── custom_fields.py
45
+ └── sync_mixins/ # one sync mixin per resource group (mirrors mixins/)
46
+ ├── __init__.py
47
+ ├── documents.py
48
+ ├── notes.py
49
+ ├── upload.py
50
+ ├── document_bulk.py
51
+ ├── non_document_bulk.py
52
+ ├── tags.py
53
+ ├── correspondents.py
54
+ ├── document_types.py
55
+ ├── storage_paths.py
56
+ └── custom_fields.py
57
+ tests/ # mirrors src/easypaperless/ structure
58
+ features/ # one spec file per feature (PROJ-X-name.md)
59
+ docs/
60
+ └── PRD.md
61
+ pyproject.toml
62
+ LICENSE
63
+ README.md
64
+ CHANGELOG.md
65
+ ```
66
+
67
+ ## Development Workflow
68
+ 1. `/requirements` - Create feature spec from idea
69
+ 2. `/architecture` - Design structure, interfaces, tech decisions (no code)
70
+ 3. `/dev` - general coder. Implement features.
71
+ 4. `/qa` - Tests, type-check, lint, edge cases, security audit
72
+ 5. `/deploy` - Package, publish (PyPI / internal), release checklist
73
+
74
+ ## Key Conventions
75
+ - **Feature IDs:** PROJ-1, PROJ-2, etc. (sequential)
76
+ - **Commits:** `feat(PROJ-X): description`, `fix(PROJ-X): description`
77
+ - **Single Responsibility:** One feature per spec file; one resource group per mixin file
78
+ - **No private leakage:** `__init__.py` defines exactly what is public
79
+ - **Human-in-the-loop:** All workflows have user approval checkpoints
80
+ - **naming conventions:** @docs/api-conventions.md
81
+ - **File size:** Keep files small and focused. Split any file that grows beyond ~200 lines into logical sub-modules (e.g. per-resource mixins). Prefer many small files over one large file.
82
+
83
+ ## Build & Test Commands
84
+ ```bash
85
+ # Activate venv (Windows)
86
+ source venv/Scripts/activate
87
+
88
+ # Install with dev dependencies
89
+ pip install -e ".[dev]"
90
+
91
+ # Run tests
92
+ pytest tests/
93
+
94
+ # Run tests with coverage
95
+ pytest tests/ --cov=easypaperless
96
+
97
+ # Lint + format check
98
+ ruff check .
99
+ ruff format --check .
100
+
101
+ # Type check
102
+ mypy src/easypaperless/
103
+
104
+ # Bump version (patch / minor / major)
105
+ hatch version patch
106
+
107
+ # Build package
108
+ hatch build
109
+
110
+ # Publish to PyPI
111
+ hatch publish
112
+
113
+ # Run integration tests (requires live paperless instance + tests/.env)
114
+ pytest tests/integration/ -m integration -v
115
+ ```
116
+
117
+ ## Product Context
118
+ @docs/PRD.md
119
+
120
+ ## Feature Overview
121
+ @features/INDEX.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Moritz Grenke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: easypaperless
3
+ Version: 0.1.0
4
+ Summary: A Python API wrapper for paperless-ngx
5
+ Project-URL: Homepage, https://github.com/TastyMojito/easypaperless
6
+ Project-URL: Repository, https://github.com/TastyMojito/easypaperless
7
+ Project-URL: Issues, https://github.com/TastyMojito/easypaperless/issues
8
+ Author-email: Moritz Grenke <info@360mix.de>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,document management,paperless,paperless-ngx,wrapper
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: httpx>=0.27
20
+ Requires-Dist: pydantic>=2.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: mypy>=1.10; extra == 'dev'
23
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
24
+ Requires-Dist: pytest-cov; extra == 'dev'
25
+ Requires-Dist: pytest>=8.0; extra == 'dev'
26
+ Requires-Dist: python-dotenv>=1.0; extra == 'dev'
27
+ Requires-Dist: respx>=0.21; extra == 'dev'
28
+ Requires-Dist: ruff>=0.4; extra == 'dev'
29
+ Provides-Extra: docs
30
+ Requires-Dist: pdoc>=14; extra == 'docs'
31
+ Provides-Extra: scripts
32
+ Requires-Dist: python-dotenv>=1.0; extra == 'scripts'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # easypaperless
36
+
37
+ [![PyPI version](https://img.shields.io/pypi/v/easypaperless.svg)](https://pypi.org/project/easypaperless/)
38
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
39
+
40
+ **easypaperless** is a high-level easy-to-use Python API wrapper for [Paperless-ngx](https://github.com/paperless-ngx/paperless-ngx).
41
+
42
+ Unlike other wrappers that simply mirror REST endpoints, **easypaperless** is designed for humans. It provides a true abstraction layer, allowing you to interact with your document management system using intuitive Python methods and objects. You don't need to understand the underlying REST API to be productive.
43
+
44
+ ---
45
+
46
+ ## ✨ Key Features
47
+
48
+ * **True Abstraction:** Focus on your logic, not on HTTP methods or JSON payloads.
49
+ * **Developer Experience (DX):** Full Type Hinting support. Your IDE (VS Code, PyCharm, etc.) will provide perfect autocompletion and documentation as you type.
50
+ * **Extensive Coverage:** Covers all essential workflows from document management to complex bulk operations.
51
+ * **Async-First with Sync Support:** Built on top of httpx, easypaperless is fully asynchronous by default for high-performance applications. But it also offers a synchronous wrapper for a classic blocking workflow.
52
+ * **Built-in Bulk Tools:** Easily manage hundreds of tags, correspondents, or documents with single-method calls.
53
+ * **Intuitive Error Hierarchy:** easypaperless provides descriptive, custom exceptions that tell you exactly what went wrong,
54
+
55
+ ---
56
+
57
+ ## 📋 Requirements
58
+
59
+ * Python: 3.11 or higher
60
+ * Paperless-ngx: 2.18 or higher (only tested with 2.18 so far)
61
+
62
+ ### Core Dependencies:
63
+
64
+ * httpx>=0.27
65
+ * Pydantic>=2.0
66
+
67
+ ---
68
+
69
+ ## 🚀 Installation
70
+
71
+ Install the package via pip:
72
+
73
+ ```bash
74
+
75
+ pip install easypaperless
76
+
77
+ ```
78
+
79
+ ---
80
+
81
+ ## 🛠 Quickstart
82
+
83
+ Get up and running in seconds. No API deep-dive required.
84
+
85
+ ### async Client
86
+
87
+ ``` Python
88
+
89
+ from easypaperless import PaperlessClient
90
+ import asyncio
91
+
92
+ async def main():
93
+
94
+ # create a paperless client
95
+ # we encourage you to use .env files to store your credentials later
96
+ async with PaperlessClient(url="http://localhost:8000", api_key="YOUR_TOKEN") as client:
97
+ # List documents — full-text search across title and OCR content, return the last three added documents
98
+ docs = await client.list_documents(search="test", max_results=3, ordering="added", descending=True)
99
+ for doc in docs:
100
+ print(f"Id: {doc.id} \nTitle: {doc.title} \nadded: {doc.added}\n")
101
+
102
+ # Fetch a single document
103
+ doc = await client.get_document(id=1)
104
+ print(doc.title, doc.created_date)
105
+
106
+ #check if a "API_edited" tag already exists - otherwise create it.
107
+ tags = await client.list_tags(name_exact="API_edited")
108
+ if not tags:
109
+ await client.create_tag(name="API_edited", color = "#40bfb7")
110
+
111
+ # Update metadata — string names are resolved to IDs automatically
112
+ await client.update_document(id=1, tags=["API_edited"])
113
+
114
+ # Upload and wait for processing to complete
115
+ #doc = await client.upload_document("path/scan.pdf", title="your title here", wait=True)
116
+ #print("Processed:", doc.id)
117
+
118
+ asyncio.run(main())
119
+
120
+ ```
121
+
122
+ ### sync Client
123
+
124
+ ``` Python
125
+
126
+ from easypaperless import SyncPaperlessClient
127
+
128
+ # same example with the sync client:
129
+ # we encourage you to use .env files to store your credentials later
130
+ with SyncPaperlessClient(url="http://localhost:8000", api_key="YOUR_TOKEN") as client:
131
+ # List documents — full-text search across title and OCR content, return the last three added documents
132
+ docs = client.list_documents(search="test", max_results=3, ordering="added", descending=True)
133
+ for doc in docs:
134
+ print(f"Id: {doc.id} \nTitle: {doc.title} \nadded: {doc.added}\n")
135
+
136
+ # Fetch a single document
137
+ doc = client.get_document(id=1)
138
+ print(doc.title, doc.created_date)
139
+
140
+ #check if a "API_edited" tag already exists - otherwise create it.
141
+ tags = client.list_tags(name_exact="API_edited")
142
+ if not tags:
143
+ client.create_tag(name="API_edited", color = "#40bfb7")
144
+
145
+ # Update metadata — string names are resolved to IDs automatically
146
+ client.update_document(id=1, tags=["API_edited"])
147
+
148
+ ```
149
+
150
+ ## 📖 Functional Overview
151
+
152
+ ### Client
153
+
154
+ * **PaperlessClient / SyncPaperlessClient** Allows token based authentication. Allows to increase timeout period for slow instances.
155
+
156
+ ### Documents
157
+
158
+ * **list_documents()** This is the workhorse of the wrapper and allows you to search for documents in your paperless-ngx instance and filter them by several criteria.
159
+ * **get_document()** Fetch a single document's data and optionally include its extended file metadata.
160
+ * **get_document_metadata()** Retrieve file-level technical metadata (checksums, sizes, MIME types) for a specific document.
161
+ * **update_document()** Partially update document fields like title, tags, or dates using PATCH semantics.
162
+ * **delete_document()** Permanently remove a document from your Paperless-ngx instance.
163
+ * **download_document()** Download the binary content of a document, either the archived PDF or the original file.
164
+ * **upload_document()** Upload a new file to Paperless-ngx and optionally wait for the processing task to complete.
165
+
166
+ ### Document Notes
167
+
168
+ * **get_notes()** Retrieve all text notes attached to a specific document.
169
+ * **create_note()** Add a new text note to an existing document.
170
+ * **delete_note()** Remove a specific note from a document.
171
+
172
+ ### Non-Document Entities
173
+
174
+ * **list_tags() / get_tag() / create_tag() / update_tag()** Manage document tags, supporting colors and matching algorithms.
175
+ * **list_correspondents() / get_correspondent() / create_correspondent()** Manage document authors, senders, or recipients.
176
+ * **list_document_types() / get_document_type() / create_document_type()** Manage categories like "Invoice," "Letter," or "Contract."
177
+ * **list_storage_paths() / get_storage_path() / create_storage_path()** Manage the physical directory structure where files are stored.
178
+ * **list_custom_fields() / get_custom_field() / create_custom_field()** Manage user-defined metadata fields for advanced document tracking.
179
+
180
+ ### Bulk Operations
181
+
182
+ * **bulk_edit()** A low-level method to execute arbitrary batch operations on a list of document IDs. It is recommended to use the high level methods below.
183
+ * **bulk_add_tag()** Add a single tag to a collection of documents in one request.
184
+ * **bulk_remove_tag()** Strip a specific tag from multiple documents simultaneously.
185
+ * **bulk_modify_tags()** Atomically add and remove multiple tags across a set of documents.
186
+ * **bulk_delete()** Permanently delete a list of documents in a single batch.
187
+ * **bulk_set_correspondent()** Assign or clear the correspondent for multiple documents at once.
188
+ * **bulk_set_document_type()** Change the document type for a group of documents in one go.
189
+ * **bulk_set_storage_path()** Update the storage path for multiple documents simultaneously.
190
+ * **bulk_modify_custom_fields()** Batch update or remove custom field values across multiple documents.
191
+ * **bulk_set_permissions()** Manage ownership and access permissions for a list of documents.
192
+
193
+ ### Bulk Operations (Non-Documents)
194
+
195
+ * **bulk_edit_objects()** A low level method to execute batch operations on system objects like tags or correspondents. It is recommended to use the high level methods below.
196
+ * **bulk_delete_tags() / bulk_delete_correspondents() / bulk_delete_document_types() / bulk_delete_storage_paths()** Batch delete various entity types to clean up your metadata.
197
+ * **bulk_set_permissions_tags() / _correspondents() / _document_types() / _storage_paths()** Batch update access control and ownership for specific metadata entities.
198
+
199
+
200
+ ## 📚 Documentation
201
+
202
+ See the 👉 [Full API Reference (pdoc)](https://tastymojito.github.io/easypaperless/)
203
+
204
+ ## 🤝 Contributing
205
+
206
+ Contributions are welcome! If you find a bug or have a feature request, please open an issue or submit a pull request.
207
+
208
+ ## 📄 License
209
+
210
+ This project is licensed under the MIT License.
211
+
212
+
@@ -0,0 +1,178 @@
1
+ # easypaperless
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/easypaperless.svg)](https://pypi.org/project/easypaperless/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ **easypaperless** is a high-level easy-to-use Python API wrapper for [Paperless-ngx](https://github.com/paperless-ngx/paperless-ngx).
7
+
8
+ Unlike other wrappers that simply mirror REST endpoints, **easypaperless** is designed for humans. It provides a true abstraction layer, allowing you to interact with your document management system using intuitive Python methods and objects. You don't need to understand the underlying REST API to be productive.
9
+
10
+ ---
11
+
12
+ ## ✨ Key Features
13
+
14
+ * **True Abstraction:** Focus on your logic, not on HTTP methods or JSON payloads.
15
+ * **Developer Experience (DX):** Full Type Hinting support. Your IDE (VS Code, PyCharm, etc.) will provide perfect autocompletion and documentation as you type.
16
+ * **Extensive Coverage:** Covers all essential workflows from document management to complex bulk operations.
17
+ * **Async-First with Sync Support:** Built on top of httpx, easypaperless is fully asynchronous by default for high-performance applications. But it also offers a synchronous wrapper for a classic blocking workflow.
18
+ * **Built-in Bulk Tools:** Easily manage hundreds of tags, correspondents, or documents with single-method calls.
19
+ * **Intuitive Error Hierarchy:** easypaperless provides descriptive, custom exceptions that tell you exactly what went wrong,
20
+
21
+ ---
22
+
23
+ ## 📋 Requirements
24
+
25
+ * Python: 3.11 or higher
26
+ * Paperless-ngx: 2.18 or higher (only tested with 2.18 so far)
27
+
28
+ ### Core Dependencies:
29
+
30
+ * httpx>=0.27
31
+ * Pydantic>=2.0
32
+
33
+ ---
34
+
35
+ ## 🚀 Installation
36
+
37
+ Install the package via pip:
38
+
39
+ ```bash
40
+
41
+ pip install easypaperless
42
+
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 🛠 Quickstart
48
+
49
+ Get up and running in seconds. No API deep-dive required.
50
+
51
+ ### async Client
52
+
53
+ ``` Python
54
+
55
+ from easypaperless import PaperlessClient
56
+ import asyncio
57
+
58
+ async def main():
59
+
60
+ # create a paperless client
61
+ # we encourage you to use .env files to store your credentials later
62
+ async with PaperlessClient(url="http://localhost:8000", api_key="YOUR_TOKEN") as client:
63
+ # List documents — full-text search across title and OCR content, return the last three added documents
64
+ docs = await client.list_documents(search="test", max_results=3, ordering="added", descending=True)
65
+ for doc in docs:
66
+ print(f"Id: {doc.id} \nTitle: {doc.title} \nadded: {doc.added}\n")
67
+
68
+ # Fetch a single document
69
+ doc = await client.get_document(id=1)
70
+ print(doc.title, doc.created_date)
71
+
72
+ #check if a "API_edited" tag already exists - otherwise create it.
73
+ tags = await client.list_tags(name_exact="API_edited")
74
+ if not tags:
75
+ await client.create_tag(name="API_edited", color = "#40bfb7")
76
+
77
+ # Update metadata — string names are resolved to IDs automatically
78
+ await client.update_document(id=1, tags=["API_edited"])
79
+
80
+ # Upload and wait for processing to complete
81
+ #doc = await client.upload_document("path/scan.pdf", title="your title here", wait=True)
82
+ #print("Processed:", doc.id)
83
+
84
+ asyncio.run(main())
85
+
86
+ ```
87
+
88
+ ### sync Client
89
+
90
+ ``` Python
91
+
92
+ from easypaperless import SyncPaperlessClient
93
+
94
+ # same example with the sync client:
95
+ # we encourage you to use .env files to store your credentials later
96
+ with SyncPaperlessClient(url="http://localhost:8000", api_key="YOUR_TOKEN") as client:
97
+ # List documents — full-text search across title and OCR content, return the last three added documents
98
+ docs = client.list_documents(search="test", max_results=3, ordering="added", descending=True)
99
+ for doc in docs:
100
+ print(f"Id: {doc.id} \nTitle: {doc.title} \nadded: {doc.added}\n")
101
+
102
+ # Fetch a single document
103
+ doc = client.get_document(id=1)
104
+ print(doc.title, doc.created_date)
105
+
106
+ #check if a "API_edited" tag already exists - otherwise create it.
107
+ tags = client.list_tags(name_exact="API_edited")
108
+ if not tags:
109
+ client.create_tag(name="API_edited", color = "#40bfb7")
110
+
111
+ # Update metadata — string names are resolved to IDs automatically
112
+ client.update_document(id=1, tags=["API_edited"])
113
+
114
+ ```
115
+
116
+ ## 📖 Functional Overview
117
+
118
+ ### Client
119
+
120
+ * **PaperlessClient / SyncPaperlessClient** Allows token based authentication. Allows to increase timeout period for slow instances.
121
+
122
+ ### Documents
123
+
124
+ * **list_documents()** This is the workhorse of the wrapper and allows you to search for documents in your paperless-ngx instance and filter them by several criteria.
125
+ * **get_document()** Fetch a single document's data and optionally include its extended file metadata.
126
+ * **get_document_metadata()** Retrieve file-level technical metadata (checksums, sizes, MIME types) for a specific document.
127
+ * **update_document()** Partially update document fields like title, tags, or dates using PATCH semantics.
128
+ * **delete_document()** Permanently remove a document from your Paperless-ngx instance.
129
+ * **download_document()** Download the binary content of a document, either the archived PDF or the original file.
130
+ * **upload_document()** Upload a new file to Paperless-ngx and optionally wait for the processing task to complete.
131
+
132
+ ### Document Notes
133
+
134
+ * **get_notes()** Retrieve all text notes attached to a specific document.
135
+ * **create_note()** Add a new text note to an existing document.
136
+ * **delete_note()** Remove a specific note from a document.
137
+
138
+ ### Non-Document Entities
139
+
140
+ * **list_tags() / get_tag() / create_tag() / update_tag()** Manage document tags, supporting colors and matching algorithms.
141
+ * **list_correspondents() / get_correspondent() / create_correspondent()** Manage document authors, senders, or recipients.
142
+ * **list_document_types() / get_document_type() / create_document_type()** Manage categories like "Invoice," "Letter," or "Contract."
143
+ * **list_storage_paths() / get_storage_path() / create_storage_path()** Manage the physical directory structure where files are stored.
144
+ * **list_custom_fields() / get_custom_field() / create_custom_field()** Manage user-defined metadata fields for advanced document tracking.
145
+
146
+ ### Bulk Operations
147
+
148
+ * **bulk_edit()** A low-level method to execute arbitrary batch operations on a list of document IDs. It is recommended to use the high level methods below.
149
+ * **bulk_add_tag()** Add a single tag to a collection of documents in one request.
150
+ * **bulk_remove_tag()** Strip a specific tag from multiple documents simultaneously.
151
+ * **bulk_modify_tags()** Atomically add and remove multiple tags across a set of documents.
152
+ * **bulk_delete()** Permanently delete a list of documents in a single batch.
153
+ * **bulk_set_correspondent()** Assign or clear the correspondent for multiple documents at once.
154
+ * **bulk_set_document_type()** Change the document type for a group of documents in one go.
155
+ * **bulk_set_storage_path()** Update the storage path for multiple documents simultaneously.
156
+ * **bulk_modify_custom_fields()** Batch update or remove custom field values across multiple documents.
157
+ * **bulk_set_permissions()** Manage ownership and access permissions for a list of documents.
158
+
159
+ ### Bulk Operations (Non-Documents)
160
+
161
+ * **bulk_edit_objects()** A low level method to execute batch operations on system objects like tags or correspondents. It is recommended to use the high level methods below.
162
+ * **bulk_delete_tags() / bulk_delete_correspondents() / bulk_delete_document_types() / bulk_delete_storage_paths()** Batch delete various entity types to clean up your metadata.
163
+ * **bulk_set_permissions_tags() / _correspondents() / _document_types() / _storage_paths()** Batch update access control and ownership for specific metadata entities.
164
+
165
+
166
+ ## 📚 Documentation
167
+
168
+ See the 👉 [Full API Reference (pdoc)](https://tastymojito.github.io/easypaperless/)
169
+
170
+ ## 🤝 Contributing
171
+
172
+ Contributions are welcome! If you find a bug or have a feature request, please open an issue or submit a pull request.
173
+
174
+ ## 📄 License
175
+
176
+ This project is licensed under the MIT License.
177
+
178
+