easypaperless
easypaperless — Python API wrapper for paperless-ngx.
1"""easypaperless — Python API wrapper for paperless-ngx.""" 2 3import importlib.metadata 4import logging 5 6__version__: str = importlib.metadata.version("easypaperless") 7 8from easypaperless import resources as resources # noqa: F401 9from easypaperless._internal.sentinel import UNSET, Unset 10from easypaperless.client import PaperlessClient 11from easypaperless.exceptions import ( 12 AuthError, 13 NotFoundError, 14 PaperlessError, 15 RetryExhaustedError, 16 ServerError, 17 TaskTimeoutError, 18 UploadError, 19 ValidationError, 20) 21from easypaperless.models import ( 22 AuditLogActor, 23 AuditLogEntry, 24 Correspondent, 25 CustomField, 26 CustomFieldValue, 27 Document, 28 DocumentMetadata, 29 DocumentNote, 30 DocumentType, 31 FieldDataType, 32 FileMetadataEntry, 33 MatchingAlgorithm, 34 PagedResult, 35 PaperlessPermission, 36 PermissionSet, 37 SearchHit, 38 SetPermissions, 39 StoragePath, 40 Tag, 41 Task, 42 TaskStatus, 43 User, 44) 45from easypaperless.sync import SyncPaperlessClient 46 47logging.getLogger("easypaperless").addHandler(logging.NullHandler()) 48 49__all__ = [ 50 "__version__", 51 # Clients 52 "PaperlessClient", 53 "SyncPaperlessClient", 54 # Sentinel 55 "UNSET", 56 "Unset", 57 # Models 58 "MatchingAlgorithm", 59 "PagedResult", 60 "AuditLogActor", 61 "AuditLogEntry", 62 "Correspondent", 63 "CustomField", 64 "CustomFieldValue", 65 "Document", 66 "DocumentMetadata", 67 "DocumentNote", 68 "DocumentType", 69 "FieldDataType", 70 "FileMetadataEntry", 71 "PermissionSet", 72 "SearchHit", 73 "SetPermissions", 74 "StoragePath", 75 "Tag", 76 "Task", 77 "TaskStatus", 78 "User", 79 "PaperlessPermission", 80 # Exceptions 81 "PaperlessError", 82 "AuthError", 83 "NotFoundError", 84 "ValidationError", 85 "ServerError", 86 "UploadError", 87 "TaskTimeoutError", 88 "RetryExhaustedError", 89]
170class PaperlessClient(_ClientCore): 171 """Async client for the paperless-ngx API. 172 173 Resources are accessible as attributes: 174 175 * ``client.correspondents`` — correspondent CRUD + bulk ops - 176 see `easypaperless.resources.CorrespondentsResource` 177 * ``client.custom_fields`` — custom field CRUD - 178 see `easypaperless.resources.CustomFieldsResource` 179 * ``client.document_types`` — document type CRUD + bulk ops - 180 see `easypaperless.resources.DocumentTypesResource` 181 * ``client.documents`` — document CRUD, bulk ops, upload, download, history - 182 see `easypaperless.resources.DocumentsResource` 183 * ``client.documents.notes`` — document notes - 184 see `easypaperless.resources.NotesResource` 185 * ``client.storage_paths`` — storage path CRUD + bulk ops - 186 see `easypaperless.resources.StoragePathsResource` 187 * ``client.tags`` — tag CRUD + bulk ops - 188 see `easypaperless.resources.TagsResource` 189 * ``client.users`` — user CRUD - 190 see `easypaperless.resources.UsersResource` 191 * ``client.trash`` — list, restore, and permanently delete trashed documents - 192 see `easypaperless.resources.TrashResource` 193 194 Use as an async context manager to ensure the underlying HTTP connection 195 pool is closed when you are done: 196 197 Example: 198 async with PaperlessClient(url="http://localhost:8000", api_token="abc") as client: 199 docs = await client.documents.list(max_results=10) 200 """ 201 202 def __init__( 203 self, 204 url: str, 205 api_token: str, 206 *, 207 timeout: float = 30.0, 208 poll_interval: float = 2.0, 209 poll_timeout: float = 60.0, 210 retry_attempts: int = 0, 211 retry_backoff: float = 1.0, 212 retry_on: tuple[type[Exception], ...] | None = None, 213 tenacity_retrying: Any = None, 214 ) -> None: 215 """Create an async paperless-ngx client. 216 217 Args: 218 url: Base URL of the paperless-ngx instance 219 (e.g. ``"http://localhost:8000"``). 220 api_token: API token. Generate one in paperless-ngx under 221 *Settings → API → Generate Token*. 222 timeout: Default request timeout in seconds. Default: ``30.0``. 223 poll_interval: Seconds between status checks when ``wait=True`` 224 is passed to :meth:`documents.upload`. Default: ``2.0``. 225 poll_timeout: Maximum seconds to wait for a document to finish 226 processing before raising 227 :exc:`~easypaperless.exceptions.TaskTimeoutError`. 228 Default: ``60.0``. 229 retry_attempts: Maximum number of retry attempts after the first 230 failure. ``0`` (the default) disables retrying entirely, 231 preserving backward-compatible behaviour. 232 retry_backoff: Initial sleep in seconds between retry attempts; 233 doubles on each subsequent attempt. Default: ``1.0``. 234 retry_on: Tuple of exception types that trigger a retry. Defaults 235 to ``(ServerError, httpx.TimeoutException, httpx.ConnectError)``. 236 ``NotFoundError`` is intentionally excluded from the default set 237 so that genuine 404 responses are never silently retried. 238 Note: ``httpx.TimeoutException`` and ``httpx.ConnectError`` are 239 intercepted inside the HTTP layer and re-raised as ``ServerError`` 240 before the retry loop runs, so including them in a custom 241 ``retry_on`` tuple has no effect unless ``ServerError`` is also 242 present. 243 tenacity_retrying: An optional pre-configured 244 ``tenacity.AsyncRetrying`` instance. When supplied, the 245 ``retry_attempts``, ``retry_backoff``, and ``retry_on`` 246 parameters are ignored and tenacity drives the retry loop 247 instead. Must be ``AsyncRetrying`` — the sync 248 ``tenacity.Retrying`` is not compatible with the async HTTP 249 layer used internally. 250 """ 251 super().__init__( 252 url, 253 api_token, 254 timeout=timeout, 255 poll_interval=poll_interval, 256 poll_timeout=poll_timeout, 257 retry_attempts=retry_attempts, 258 retry_backoff=retry_backoff, 259 retry_on=retry_on, 260 tenacity_retrying=tenacity_retrying, 261 ) 262 263 async def __aenter__(self) -> PaperlessClient: 264 return self 265 266 async def __aexit__(self, *args: Any) -> None: 267 await self.close()
Async client for the paperless-ngx API.
Resources are accessible as attributes:
client.correspondents— correspondent CRUD + bulk ops - seeeasypaperless.resources.CorrespondentsResourceclient.custom_fields— custom field CRUD - seeeasypaperless.resources.CustomFieldsResourceclient.document_types— document type CRUD + bulk ops - seeeasypaperless.resources.DocumentTypesResourceclient.documents— document CRUD, bulk ops, upload, download, history - seeeasypaperless.resources.DocumentsResourceclient.documents.notes— document notes - seeeasypaperless.resources.NotesResourceclient.storage_paths— storage path CRUD + bulk ops - seeeasypaperless.resources.StoragePathsResourceclient.tags— tag CRUD + bulk ops - seeeasypaperless.resources.TagsResourceclient.users— user CRUD - seeeasypaperless.resources.UsersResourceclient.trash— list, restore, and permanently delete trashed documents - seeeasypaperless.resources.TrashResource
Use as an async context manager to ensure the underlying HTTP connection pool is closed when you are done:
Example:
async with PaperlessClient(url="http://localhost:8000", api_token="abc") as client: docs = await client.documents.list(max_results=10)
202 def __init__( 203 self, 204 url: str, 205 api_token: str, 206 *, 207 timeout: float = 30.0, 208 poll_interval: float = 2.0, 209 poll_timeout: float = 60.0, 210 retry_attempts: int = 0, 211 retry_backoff: float = 1.0, 212 retry_on: tuple[type[Exception], ...] | None = None, 213 tenacity_retrying: Any = None, 214 ) -> None: 215 """Create an async paperless-ngx client. 216 217 Args: 218 url: Base URL of the paperless-ngx instance 219 (e.g. ``"http://localhost:8000"``). 220 api_token: API token. Generate one in paperless-ngx under 221 *Settings → API → Generate Token*. 222 timeout: Default request timeout in seconds. Default: ``30.0``. 223 poll_interval: Seconds between status checks when ``wait=True`` 224 is passed to :meth:`documents.upload`. Default: ``2.0``. 225 poll_timeout: Maximum seconds to wait for a document to finish 226 processing before raising 227 :exc:`~easypaperless.exceptions.TaskTimeoutError`. 228 Default: ``60.0``. 229 retry_attempts: Maximum number of retry attempts after the first 230 failure. ``0`` (the default) disables retrying entirely, 231 preserving backward-compatible behaviour. 232 retry_backoff: Initial sleep in seconds between retry attempts; 233 doubles on each subsequent attempt. Default: ``1.0``. 234 retry_on: Tuple of exception types that trigger a retry. Defaults 235 to ``(ServerError, httpx.TimeoutException, httpx.ConnectError)``. 236 ``NotFoundError`` is intentionally excluded from the default set 237 so that genuine 404 responses are never silently retried. 238 Note: ``httpx.TimeoutException`` and ``httpx.ConnectError`` are 239 intercepted inside the HTTP layer and re-raised as ``ServerError`` 240 before the retry loop runs, so including them in a custom 241 ``retry_on`` tuple has no effect unless ``ServerError`` is also 242 present. 243 tenacity_retrying: An optional pre-configured 244 ``tenacity.AsyncRetrying`` instance. When supplied, the 245 ``retry_attempts``, ``retry_backoff``, and ``retry_on`` 246 parameters are ignored and tenacity drives the retry loop 247 instead. Must be ``AsyncRetrying`` — the sync 248 ``tenacity.Retrying`` is not compatible with the async HTTP 249 layer used internally. 250 """ 251 super().__init__( 252 url, 253 api_token, 254 timeout=timeout, 255 poll_interval=poll_interval, 256 poll_timeout=poll_timeout, 257 retry_attempts=retry_attempts, 258 retry_backoff=retry_backoff, 259 retry_on=retry_on, 260 tenacity_retrying=tenacity_retrying, 261 )
Create an async paperless-ngx client.
Arguments:
- url: Base URL of the paperless-ngx instance
(e.g.
"http://localhost:8000"). - api_token: API token. Generate one in paperless-ngx under Settings → API → Generate Token.
- timeout: Default request timeout in seconds. Default:
30.0. - poll_interval: Seconds between status checks when
wait=Trueis passed todocuments.upload(). Default:2.0. - poll_timeout: Maximum seconds to wait for a document to finish
processing before raising
~easypaperless.exceptions.TaskTimeoutError. Default:60.0. - retry_attempts: Maximum number of retry attempts after the first
failure.
0(the default) disables retrying entirely, preserving backward-compatible behaviour. - retry_backoff: Initial sleep in seconds between retry attempts;
doubles on each subsequent attempt. Default:
1.0. - retry_on: Tuple of exception types that trigger a retry. Defaults
to
(ServerError, httpx.TimeoutException, httpx.ConnectError).NotFoundErroris intentionally excluded from the default set so that genuine 404 responses are never silently retried. Note:httpx.TimeoutExceptionandhttpx.ConnectErrorare intercepted inside the HTTP layer and re-raised asServerErrorbefore the retry loop runs, so including them in a customretry_ontuple has no effect unlessServerErroris also present. - tenacity_retrying: An optional pre-configured
tenacity.AsyncRetryinginstance. When supplied, theretry_attempts,retry_backoff, andretry_onparameters are ignored and tenacity drives the retry loop instead. Must beAsyncRetrying— the synctenacity.Retryingis not compatible with the async HTTP layer used internally.
83class SyncPaperlessClient(_SyncCore): 84 """Synchronous interface to paperless-ngx. 85 86 Resources are accessible as attributes: 87 88 * ``client.correspondents`` — correspondent CRUD + bulk ops - 89 see `easypaperless.resources.SyncCorrespondentsResource` 90 * ``client.custom_fields`` — custom field CRUD - 91 see `easypaperless.resources.SyncCustomFieldsResource` 92 * ``client.document_types`` — document type CRUD + bulk ops - 93 see `easypaperless.resources.SyncDocumentTypesResource` 94 * ``client.documents`` — document CRUD, bulk ops, upload, download - 95 see `easypaperless.resources.SyncDocumentsResource` 96 * ``client.documents.notes`` — document notes - 97 see `easypaperless.resources.SyncNotesResource` 98 * ``client.storage_paths`` — storage path CRUD + bulk ops - 99 see `easypaperless.resources.SyncStoragePathsResource` 100 * ``client.tags`` — tag CRUD + bulk ops - 101 see `easypaperless.resources.SyncTagsResource` 102 * ``client.users`` — user CRUD - 103 see `easypaperless.resources.SyncUsersResource` 104 * ``client.trash`` — list, restore, and permanently delete trashed documents - 105 see `easypaperless.resources.SyncTrashResource` 106 107 All methods are synchronous wrappers around the async 108 :class:`~easypaperless.client.PaperlessClient`. Operations run on a 109 dedicated background event loop thread so that the httpx connection pool 110 is reused across calls and cleanup works correctly. 111 112 Use as a context manager to ensure proper cleanup: 113 114 Example: 115 with SyncPaperlessClient(url="http://localhost:8000", api_token="abc") as client: 116 tags = client.tags.list() 117 docs = client.documents.list(search="invoice") 118 119 Note: 120 Cannot be used inside an already-running event loop (e.g. Jupyter 121 notebooks). Use :class:`~easypaperless.client.PaperlessClient` 122 directly in those environments. 123 """ 124 125 def __init__(self, url: str, api_token: str, **kwargs: Any) -> None: 126 """Create a synchronous paperless-ngx client. 127 128 Args: 129 url: Base URL of the paperless-ngx instance 130 (e.g. ``"http://localhost:8000"``). 131 api_token: API token. Generate one in paperless-ngx under 132 *Settings → API → Generate Token*. 133 **kwargs: Additional keyword arguments forwarded to 134 :class:`~easypaperless.client.PaperlessClient` (e.g. 135 ``poll_interval``, ``poll_timeout``, ``retry_attempts``, 136 ``retry_backoff``, ``retry_on``, ``tenacity_retrying``). 137 When using ``tenacity_retrying``, pass a 138 ``tenacity.AsyncRetrying`` instance — the sync 139 ``tenacity.Retrying`` is not compatible because all requests 140 run on an internal async event loop. 141 """ 142 super().__init__(url, api_token, **kwargs) 143 144 def __enter__(self) -> SyncPaperlessClient: 145 return self 146 147 def __exit__(self, *args: Any) -> None: 148 self.close()
Synchronous interface to paperless-ngx.
Resources are accessible as attributes:
client.correspondents— correspondent CRUD + bulk ops - seeeasypaperless.resources.SyncCorrespondentsResourceclient.custom_fields— custom field CRUD - seeeasypaperless.resources.SyncCustomFieldsResourceclient.document_types— document type CRUD + bulk ops - seeeasypaperless.resources.SyncDocumentTypesResourceclient.documents— document CRUD, bulk ops, upload, download - seeeasypaperless.resources.SyncDocumentsResourceclient.documents.notes— document notes - seeeasypaperless.resources.SyncNotesResourceclient.storage_paths— storage path CRUD + bulk ops - seeeasypaperless.resources.SyncStoragePathsResourceclient.tags— tag CRUD + bulk ops - seeeasypaperless.resources.SyncTagsResourceclient.users— user CRUD - seeeasypaperless.resources.SyncUsersResourceclient.trash— list, restore, and permanently delete trashed documents - seeeasypaperless.resources.SyncTrashResource
All methods are synchronous wrappers around the async
~easypaperless.client.PaperlessClient. Operations run on a
dedicated background event loop thread so that the httpx connection pool
is reused across calls and cleanup works correctly.
Use as a context manager to ensure proper cleanup:
Example:
with SyncPaperlessClient(url="http://localhost:8000", api_token="abc") as client: tags = client.tags.list() docs = client.documents.list(search="invoice")
Note:
Cannot be used inside an already-running event loop (e.g. Jupyter notebooks). Use
~easypaperless.client.PaperlessClientdirectly in those environments.
125 def __init__(self, url: str, api_token: str, **kwargs: Any) -> None: 126 """Create a synchronous paperless-ngx client. 127 128 Args: 129 url: Base URL of the paperless-ngx instance 130 (e.g. ``"http://localhost:8000"``). 131 api_token: API token. Generate one in paperless-ngx under 132 *Settings → API → Generate Token*. 133 **kwargs: Additional keyword arguments forwarded to 134 :class:`~easypaperless.client.PaperlessClient` (e.g. 135 ``poll_interval``, ``poll_timeout``, ``retry_attempts``, 136 ``retry_backoff``, ``retry_on``, ``tenacity_retrying``). 137 When using ``tenacity_retrying``, pass a 138 ``tenacity.AsyncRetrying`` instance — the sync 139 ``tenacity.Retrying`` is not compatible because all requests 140 run on an internal async event loop. 141 """ 142 super().__init__(url, api_token, **kwargs)
Create a synchronous paperless-ngx client.
Arguments:
- url: Base URL of the paperless-ngx instance
(e.g.
"http://localhost:8000"). - api_token: API token. Generate one in paperless-ngx under Settings → API → Generate Token.
- **kwargs: Additional keyword arguments forwarded to
~easypaperless.client.PaperlessClient(e.g.poll_interval,poll_timeout,retry_attempts,retry_backoff,retry_on,tenacity_retrying). When usingtenacity_retrying, pass atenacity.AsyncRetryinginstance — the synctenacity.Retryingis not compatible because all requests run on an internal async event loop.
9class Unset: 10 """Sentinel type signalling that a parameter was not provided. 11 12 Use the singleton :data:`UNSET` constant — do not instantiate directly. 13 """ 14 15 __slots__ = () 16 17 def __repr__(self) -> str: 18 return "UNSET"
Sentinel type signalling that a parameter was not provided.
Use the singleton UNSET constant — do not instantiate directly.
9class MatchingAlgorithm(IntEnum): 10 """Auto-matching algorithm used by tags, correspondents, document types, and storage paths.""" 11 12 NONE = 0 13 ANY_WORD = 1 14 ALL_WORDS = 2 15 EXACT = 3 16 REGEX = 4 17 FUZZY = 5 18 AUTO = 6
Auto-matching algorithm used by tags, correspondents, document types, and storage paths.
13class PagedResult(BaseModel, Generic[T]): 14 """Wrapper returned by all ``list()`` methods. 15 16 Holds the pagination metadata returned by paperless-ngx alongside the 17 deserialized resource items. 18 19 Attributes: 20 count: Total number of matching items as reported by the server on 21 the first fetched page. 22 next: URL of the next page as returned by the API, or ``None``. 23 Always ``None`` when auto-pagination is active (the default 24 ``page=None``), because the navigation URL is meaningless once 25 all pages have been consumed by the library. 26 previous: URL of the previous page as returned by the API, or 27 ``None``. Always ``None`` when auto-pagination is active. 28 all: All matching item IDs when the API includes them; ``None`` 29 otherwise. 30 results: The deserialized resource items for this page / all fetched 31 pages. 32 """ 33 34 count: int 35 next: str | None = None 36 previous: str | None = None 37 all: List[int] | None = None 38 results: List[T] = Field(default_factory=list)
Wrapper returned by all list() methods.
Holds the pagination metadata returned by paperless-ngx alongside the deserialized resource items.
Attributes:
- count: Total number of matching items as reported by the server on the first fetched page.
- next: URL of the next page as returned by the API, or
None. AlwaysNonewhen auto-pagination is active (the defaultpage=None), because the navigation URL is meaningless once all pages have been consumed by the library. - previous: URL of the previous page as returned by the API, or
None. AlwaysNonewhen auto-pagination is active. - all: All matching item IDs when the API includes them;
Noneotherwise. - results: The deserialized resource items for this page / all fetched pages.
82class AuditLogActor(BaseModel): 83 """The user who performed an audited action. 84 85 Attributes: 86 id: Numeric user ID. 87 username: Username of the actor. 88 """ 89 90 model_config = ConfigDict(extra="ignore") 91 92 id: int 93 username: str
The user who performed an audited action.
Attributes:
- id: Numeric user ID.
- username: Username of the actor.
96class AuditLogEntry(BaseModel): 97 """A single entry in a document's audit log. 98 99 Attributes: 100 id: Unique audit log entry ID. 101 timestamp: When the action occurred. 102 action: Action type (e.g. ``"create"``, ``"update"``). 103 changes: Free-form dict describing what changed. Keys and value 104 shapes vary by action type. 105 actor: The user who performed the action, or ``None`` for 106 system-generated entries. 107 """ 108 109 model_config = ConfigDict(extra="ignore") 110 111 id: int 112 timestamp: datetime 113 action: str 114 changes: dict[str, Any] 115 actor: AuditLogActor | None = None
A single entry in a document's audit log.
Attributes:
- id: Unique audit log entry ID.
- timestamp: When the action occurred.
- action: Action type (e.g.
"create","update"). - changes: Free-form dict describing what changed. Keys and value shapes vary by action type.
- actor: The user who performed the action, or
Nonefor system-generated entries.
13class Correspondent(BaseModel): 14 """A paperless-ngx correspondent (sender or recipient of a document). 15 16 Attributes: 17 id: Unique correspondent ID. 18 name: Correspondent name. 19 document_count: Number of documents assigned to this correspondent. 20 last_correspondence: Date of the most recent document assigned here, 21 or ``None``. 22 """ 23 24 model_config = ConfigDict(extra="ignore") 25 26 id: int 27 name: str 28 slug: str | None = None 29 match: str | None = None 30 matching_algorithm: MatchingAlgorithm | None = None 31 is_insensitive: bool | None = None 32 document_count: int | None = None 33 last_correspondence: date | None = None 34 owner: int | None = None 35 user_can_change: bool | None = None
A paperless-ngx correspondent (sender or recipient of a document).
Attributes:
- id: Unique correspondent ID.
- name: Correspondent name.
- document_count: Number of documents assigned to this correspondent.
- last_correspondence: Date of the most recent document assigned here,
or
None.
26class CustomField(BaseModel): 27 """A custom field definition in paperless-ngx. 28 29 Attributes: 30 id: Unique custom-field ID. 31 name: Field name shown in the UI. 32 data_type: The value type for this field (see 33 :class:`FieldDataType`). 34 extra_data: Additional configuration (e.g. select options), or 35 ``None``. 36 document_count: Number of documents that have a value for this field. 37 """ 38 39 model_config = ConfigDict(extra="ignore") 40 41 id: int 42 name: str 43 data_type: FieldDataType 44 extra_data: Any = None 45 document_count: int | None = None
A custom field definition in paperless-ngx.
Attributes:
- id: Unique custom-field ID.
- name: Field name shown in the UI.
- data_type: The value type for this field (see
FieldDataType). - extra_data: Additional configuration (e.g. select options), or
None. - document_count: Number of documents that have a value for this field.
66class CustomFieldValue(BaseModel): 67 """A custom field value attached to a document. 68 69 Attributes: 70 field: ID of the :class:`~easypaperless.models.custom_fields.CustomField` 71 definition. 72 value: The stored value; its Python type depends on the field's 73 ``data_type``. 74 """ 75 76 model_config = ConfigDict(extra="ignore") 77 78 field: int 79 value: Any = None
A custom field value attached to a document.
Attributes:
- field: ID of the
~easypaperless.models.custom_fields.CustomFielddefinition. - value: The stored value; its Python type depends on the field's
data_type.
209class Document(BaseModel): 210 """A paperless-ngx document. 211 212 Attributes: 213 id: Unique document ID. 214 title: Document title. 215 content: Full OCR text content, if available. 216 tags: List of tag IDs assigned to this document. 217 document_type: ID of the assigned document type, or ``None``. 218 correspondent: ID of the assigned correspondent, or ``None``. 219 storage_path: ID of the assigned storage path, or ``None``. 220 created: Document creation date (``date`` object). Changed from 221 ``datetime`` to ``date`` in paperless-ngx API v9. 222 created_date: Date portion of creation. **Deprecated** by 223 paperless-ngx as of v9 — use ``created`` instead. Will be 224 removed in a future API version. 225 archive_serial_number: Archive serial number (ASN), or ``None``. 226 custom_fields: List of :class:`CustomFieldValue` instances. 227 notes: User notes attached to this document. 228 search_hit: Full-text search relevance metadata, populated only when 229 the document was returned by a full-text search. 230 metadata: Extended file-level metadata (checksums, sizes, MIME type). 231 ``None`` unless the document was fetched with 232 ``include_metadata=True`` or retrieved via 233 :meth:`~easypaperless._internal.resources.documents.DocumentsResource.get_metadata`. 234 """ 235 236 model_config = ConfigDict(extra="ignore", populate_by_name=True) 237 238 id: int 239 title: str 240 content: str | None = None 241 tags: list[int] = Field(default_factory=list) 242 document_type: int | None = None 243 correspondent: int | None = None 244 storage_path: int | None = None 245 created: date | None = None 246 created_date: date | None = None 247 modified: datetime | None = None 248 added: datetime | None = None 249 archive_serial_number: int | None = None 250 original_file_name: str | None = None 251 archived_file_name: str | None = None 252 owner: int | None = None 253 user_can_change: bool | None = None 254 is_shared_by_requester: bool | None = None 255 notes: list[DocumentNote] = Field(default_factory=list) 256 custom_fields: list[CustomFieldValue] = Field(default_factory=list) 257 search_hit: SearchHit | None = Field(default=None, alias="__search_hit__") 258 metadata: DocumentMetadata | None = None
A paperless-ngx document.
Attributes:
- id: Unique document ID.
- title: Document title.
- content: Full OCR text content, if available.
- tags: List of tag IDs assigned to this document.
- document_type: ID of the assigned document type, or
None. - correspondent: ID of the assigned correspondent, or
None. - storage_path: ID of the assigned storage path, or
None. - created: Document creation date (
dateobject). Changed fromdatetimetodatein paperless-ngx API v9. - created_date: Date portion of creation. Deprecated by
paperless-ngx as of v9 — use
createdinstead. Will be removed in a future API version. - archive_serial_number: Archive serial number (ASN), or
None. - custom_fields: List of
CustomFieldValueinstances. - notes: User notes attached to this document.
- search_hit: Full-text search relevance metadata, populated only when the document was returned by a full-text search.
- metadata: Extended file-level metadata (checksums, sizes, MIME type).
Noneunless the document was fetched withinclude_metadata=Trueor retrieved via~easypaperless._internal.resources.documents.DocumentsResource.get_metadata().
167class DocumentMetadata(BaseModel): 168 """Extended file-level metadata for a document. 169 170 Returned by ``GET /api/documents/{id}/metadata/`` and optionally attached 171 to a :class:`Document` when 172 :meth:`~easypaperless._internal.resources.documents.DocumentsResource.get` 173 is called with ``include_metadata=True``. 174 175 Because reading metadata requires disk I/O it is **not** included in 176 document list responses; it must be requested explicitly. 177 178 Attributes: 179 original_checksum: MD5 checksum of the original uploaded file. 180 original_size: Size of the original file in bytes. 181 original_mime_type: MIME type of the original file 182 (e.g. ``"application/pdf"``). 183 media_filename: Path of the archived file relative to the 184 paperless-ngx media root. 185 has_archive_version: ``True`` when paperless-ngx has produced an 186 archived (post-processed) PDF in addition to the original. 187 original_metadata: File-level metadata entries extracted from the 188 original document (PDF XMP/info tags, etc.). 189 archive_checksum: MD5 checksum of the archived file, or ``None`` if 190 no archive version exists. 191 archive_size: Size of the archived file in bytes, or ``None``. 192 archive_metadata: File-level metadata entries from the archived 193 document, or ``None``. 194 """ 195 196 model_config = ConfigDict(extra="ignore") 197 198 original_checksum: str | None = None 199 original_size: int | None = None 200 original_mime_type: str | None = None 201 media_filename: str | None = None 202 has_archive_version: bool | None = None 203 original_metadata: list[FileMetadataEntry] = Field(default_factory=list) 204 archive_checksum: str | None = None 205 archive_size: int | None = None 206 archive_metadata: list[FileMetadataEntry] | None = None
Extended file-level metadata for a document.
Returned by GET /api/documents/{id}/metadata/ and optionally attached
to a Document when
~easypaperless._internal.resources.documents.DocumentsResource.get()
is called with include_metadata=True.
Because reading metadata requires disk I/O it is not included in document list responses; it must be requested explicitly.
Attributes:
- original_checksum: MD5 checksum of the original uploaded file.
- original_size: Size of the original file in bytes.
- original_mime_type: MIME type of the original file
(e.g.
"application/pdf"). - media_filename: Path of the archived file relative to the paperless-ngx media root.
- has_archive_version:
Truewhen paperless-ngx has produced an archived (post-processed) PDF in addition to the original. - original_metadata: File-level metadata entries extracted from the original document (PDF XMP/info tags, etc.).
- archive_checksum: MD5 checksum of the archived file, or
Noneif no archive version exists. - archive_size: Size of the archived file in bytes, or
None. - archive_metadata: File-level metadata entries from the archived
document, or
None.
118class DocumentNote(BaseModel): 119 """A user note attached to a document. 120 121 Attributes: 122 id: Unique note ID. 123 note: Text content of the note. 124 created: Timestamp when the note was created. 125 document: ID of the parent document. 126 user: ID of the user who created the note. 127 """ 128 129 model_config = ConfigDict(extra="ignore") 130 131 id: int | None = None 132 note: str 133 created: datetime | None = None 134 document: int | None = None 135 user: int | None = None 136 137 @field_validator("user", mode="before") 138 @classmethod 139 def _coerce_user(cls, v: object) -> int | None: 140 if isinstance(v, dict): 141 return v.get("id") 142 return v # type: ignore[return-value]
A user note attached to a document.
Attributes:
- id: Unique note ID.
- note: Text content of the note.
- created: Timestamp when the note was created.
- document: ID of the parent document.
- user: ID of the user who created the note.
11class DocumentType(BaseModel): 12 """A paperless-ngx document type (e.g. Invoice, Receipt, Contract). 13 14 Attributes: 15 id: Unique document-type ID. 16 name: Document-type name. 17 document_count: Number of documents assigned to this document type. 18 """ 19 20 model_config = ConfigDict(extra="ignore") 21 22 id: int 23 name: str 24 slug: str | None = None 25 match: str | None = None 26 matching_algorithm: MatchingAlgorithm | None = None 27 is_insensitive: bool | None = None 28 document_count: int | None = None 29 owner: int | None = None 30 user_can_change: bool | None = None
A paperless-ngx document type (e.g. Invoice, Receipt, Contract).
Attributes:
- id: Unique document-type ID.
- name: Document-type name.
- document_count: Number of documents assigned to this document type.
12class FieldDataType(StrEnum): 13 """Allowed data types for a custom field.""" 14 15 string = "string" 16 boolean = "boolean" 17 integer = "integer" 18 float = "float" 19 monetary = "monetary" 20 date = "date" 21 url = "url" 22 documentlink = "documentlink" 23 select = "select"
Allowed data types for a custom field.
145class FileMetadataEntry(BaseModel): 146 """A single embedded metadata key-value pair from a document file. 147 148 Paperless-ngx reads file-level metadata (e.g. PDF XMP/info tags) and 149 exposes each entry in this format. ``namespace`` and ``prefix`` are 150 ``None`` for non-namespaced entries. 151 152 Attributes: 153 namespace: XML namespace URI, or ``None``. 154 prefix: Namespace prefix (e.g. ``"pdf"``), or ``None``. 155 key: Metadata key (e.g. ``"Producer"``). 156 value: Metadata value as a string. 157 """ 158 159 model_config = ConfigDict(extra="ignore") 160 161 namespace: str | None = None 162 prefix: str | None = None 163 key: str 164 value: str
A single embedded metadata key-value pair from a document file.
Paperless-ngx reads file-level metadata (e.g. PDF XMP/info tags) and
exposes each entry in this format. namespace and prefix are
None for non-namespaced entries.
Attributes:
- namespace: XML namespace URI, or
None. - prefix: Namespace prefix (e.g.
"pdf"), orNone. - key: Metadata key (e.g.
"Producer"). - value: Metadata value as a string.
7class PermissionSet(BaseModel): 8 users: list[int] = Field(default_factory=list) 9 groups: list[int] = Field(default_factory=list)
!!! abstract "Usage Documentation" Models
A base class for creating Pydantic models.
Attributes:
- __class_vars__: The names of the class variables defined on the model.
- __private_attributes__: Metadata about the private attributes of the model.
- __signature__: The synthesized
__init__[Signature][inspect.Signature] of the model. - __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
- __pydantic_core_schema__: The core schema of the model.
- __pydantic_custom_init__: Whether the model has a custom
__init__function. - __pydantic_decorators__: Metadata containing the decorators defined on the model.
This replaces
Model.__validators__andModel.__root_validators__from Pydantic V1. - __pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
- __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
- __pydantic_post_init__: The name of the post-init method for the model, if defined.
- __pydantic_root_model__: Whether the model is a [
RootModel][pydantic.root_model.RootModel]. - __pydantic_serializer__: The
pydantic-coreSchemaSerializerused to dump instances of the model. - __pydantic_validator__: The
pydantic-coreSchemaValidatorused to validate instances of the model. - __pydantic_fields__: A dictionary of field names and their corresponding [
FieldInfo][pydantic.fields.FieldInfo] objects. - __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [
ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects. - __pydantic_extra__: A dictionary containing extra values, if [
extra][pydantic.config.ConfigDict.extra] is set to'allow'. - __pydantic_fields_set__: The names of fields explicitly set during instantiation.
- __pydantic_private__: Values of private attributes set on the model instance.
49class SearchHit(BaseModel): 50 """Full-text search relevance metadata returned alongside a document. 51 52 Attributes: 53 score: Relevance score assigned by the Whoosh FTS engine. 54 highlights: HTML snippet with matching terms highlighted. 55 rank: Position in the result set by relevance. 56 """ 57 58 model_config = ConfigDict(extra="ignore") 59 60 score: float | None = None 61 highlights: str | None = None 62 note_highlights: str | None = None 63 rank: int | None = None
Full-text search relevance metadata returned alongside a document.
Attributes:
- score: Relevance score assigned by the Whoosh FTS engine.
- highlights: HTML snippet with matching terms highlighted.
- rank: Position in the result set by relevance.
12class SetPermissions(BaseModel): 13 view: PermissionSet = Field(default_factory=PermissionSet) 14 change: PermissionSet = Field(default_factory=PermissionSet)
!!! abstract "Usage Documentation" Models
A base class for creating Pydantic models.
Attributes:
- __class_vars__: The names of the class variables defined on the model.
- __private_attributes__: Metadata about the private attributes of the model.
- __signature__: The synthesized
__init__[Signature][inspect.Signature] of the model. - __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
- __pydantic_core_schema__: The core schema of the model.
- __pydantic_custom_init__: Whether the model has a custom
__init__function. - __pydantic_decorators__: Metadata containing the decorators defined on the model.
This replaces
Model.__validators__andModel.__root_validators__from Pydantic V1. - __pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
- __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
- __pydantic_post_init__: The name of the post-init method for the model, if defined.
- __pydantic_root_model__: Whether the model is a [
RootModel][pydantic.root_model.RootModel]. - __pydantic_serializer__: The
pydantic-coreSchemaSerializerused to dump instances of the model. - __pydantic_validator__: The
pydantic-coreSchemaValidatorused to validate instances of the model. - __pydantic_fields__: A dictionary of field names and their corresponding [
FieldInfo][pydantic.fields.FieldInfo] objects. - __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [
ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects. - __pydantic_extra__: A dictionary containing extra values, if [
extra][pydantic.config.ConfigDict.extra] is set to'allow'. - __pydantic_fields_set__: The names of fields explicitly set during instantiation.
- __pydantic_private__: Values of private attributes set on the model instance.
11class StoragePath(BaseModel): 12 """A paperless-ngx storage path — controls where archived files are stored. 13 14 Attributes: 15 id: Unique storage-path ID. 16 name: Storage-path name. 17 path: Template string used to build the storage path, e.g. 18 ``"{created_year}/{correspondent}/{title}"``. 19 document_count: Number of documents using this storage path. 20 """ 21 22 model_config = ConfigDict(extra="ignore") 23 24 id: int 25 name: str 26 slug: str | None = None 27 path: str | None = None 28 match: str | None = None 29 matching_algorithm: MatchingAlgorithm | None = None 30 is_insensitive: bool | None = None 31 document_count: int | None = None 32 owner: int | None = None 33 user_can_change: bool | None = None
A paperless-ngx storage path — controls where archived files are stored.
Attributes:
- id: Unique storage-path ID.
- name: Storage-path name.
- path: Template string used to build the storage path, e.g.
"{created_year}/{correspondent}/{title}". - document_count: Number of documents using this storage path.
11class Tag(BaseModel): 12 """A paperless-ngx tag. 13 14 Attributes: 15 id: Unique tag ID. 16 name: Tag name. 17 color: Hex colour code used in the UI (e.g. ``"#ff0000"``). 18 is_inbox_tag: If ``True``, newly ingested documents receive this tag 19 automatically until they are processed. 20 document_count: Number of documents currently assigned to this tag. 21 parent: ID of the parent tag for hierarchical tag trees, or ``None``. 22 children: IDs of child tags, or ``None``. 23 """ 24 25 model_config = ConfigDict(extra="ignore") 26 27 id: int 28 name: str 29 slug: str | None = None 30 color: str | None = None 31 text_color: str | None = None 32 match: str | None = None 33 matching_algorithm: MatchingAlgorithm | None = None 34 is_insensitive: bool | None = None 35 is_inbox_tag: bool | None = None 36 document_count: int | None = None 37 owner: int | None = None 38 user_can_change: bool | None = None 39 parent: int | None = None 40 children: list[int] | None = None
A paperless-ngx tag.
Attributes:
- id: Unique tag ID.
- name: Tag name.
- color: Hex colour code used in the UI (e.g.
"#ff0000"). - is_inbox_tag: If
True, newly ingested documents receive this tag automatically until they are processed. - document_count: Number of documents currently assigned to this tag.
- parent: ID of the parent tag for hierarchical tag trees, or
None. - children: IDs of child tags, or
None.
24class Task(BaseModel): 25 """A paperless-ngx background processing task (e.g. document ingestion). 26 27 Attributes: 28 task_id: Unique Celery task identifier. 29 task_file_name: Original file name submitted for processing. 30 status: Current task status as a :class:`TaskStatus` enum value. 31 result: Human-readable result or error message, set on completion. 32 related_document: String representation of the resulting document ID 33 on success, ``None`` otherwise. 34 """ 35 36 model_config = ConfigDict(extra="ignore") 37 38 task_id: str 39 task_file_name: str | None = None 40 date_created: datetime | None = None 41 date_done: datetime | None = None 42 type: str | None = None 43 status: TaskStatus | None = None 44 result: str | None = None 45 acknowledged: bool | None = None 46 related_document: str | None = None
A paperless-ngx background processing task (e.g. document ingestion).
Attributes:
- task_id: Unique Celery task identifier.
- task_file_name: Original file name submitted for processing.
- status: Current task status as a
TaskStatusenum value. - result: Human-readable result or error message, set on completion.
- related_document: String representation of the resulting document ID
on success,
Noneotherwise.
13class TaskStatus(StrEnum): 14 """Status values for a paperless-ngx background processing task.""" 15 16 PENDING = "PENDING" 17 STARTED = "STARTED" 18 SUCCESS = "SUCCESS" 19 FAILURE = "FAILURE" 20 RETRY = "RETRY" 21 REVOKED = "REVOKED"
Status values for a paperless-ngx background processing task.
205class User(BaseModel): 206 """A paperless-ngx user account. 207 208 Attributes: 209 id: Unique user ID (set by the API). 210 username: Login username. 211 email: Email address. 212 password: Password field as returned by the API (write-only in practice). 213 first_name: Given name. 214 last_name: Family name. 215 date_joined: Timestamp of account creation. 216 is_staff: Whether the user has staff (admin UI) access. 217 is_active: Whether the account is active. 218 is_superuser: Whether the user has unrestricted superuser access. 219 groups: IDs of groups the user belongs to. 220 user_permissions: Directly assigned permission strings. 221 inherited_permissions: Effective permissions inherited from groups 222 (read-only, not sent on create/update). 223 is_mfa_enabled: Whether multi-factor authentication is enabled 224 (read-only, not sent on create/update). 225 """ 226 227 model_config = ConfigDict(extra="ignore") 228 229 id: int 230 username: str 231 email: str | None = None 232 password: str | None = None 233 first_name: str | None = None 234 last_name: str | None = None 235 date_joined: datetime | None = None 236 is_staff: bool | None = None 237 is_active: bool | None = None 238 is_superuser: bool | None = None 239 groups: list[int] | None = None 240 user_permissions: list[str] | None = None 241 inherited_permissions: list[str] | None = None 242 is_mfa_enabled: bool | None = None
A paperless-ngx user account.
Attributes:
- id: Unique user ID (set by the API).
- username: Login username.
- email: Email address.
- password: Password field as returned by the API (write-only in practice).
- first_name: Given name.
- last_name: Family name.
- date_joined: Timestamp of account creation.
- is_staff: Whether the user has staff (admin UI) access.
- is_active: Whether the account is active.
- is_superuser: Whether the user has unrestricted superuser access.
- groups: IDs of groups the user belongs to.
- user_permissions: Directly assigned permission strings.
- inherited_permissions: Effective permissions inherited from groups (read-only, not sent on create/update).
- is_mfa_enabled: Whether multi-factor authentication is enabled (read-only, not sent on create/update).
7class PaperlessError(Exception): 8 """Base exception for all easypaperless errors. 9 10 Attributes: 11 status_code: The HTTP status code associated with the error, or 12 ``None`` for non-HTTP errors (e.g. timeouts, local validation). 13 """ 14 15 def __init__(self, message: str, status_code: int | None = None) -> None: 16 """Create a PaperlessError. 17 18 Args: 19 message: Human-readable error description. 20 status_code: HTTP status code, if applicable. 21 """ 22 super().__init__(message) 23 self.status_code = status_code
Base exception for all easypaperless errors.
Attributes:
- status_code: The HTTP status code associated with the error, or
Nonefor non-HTTP errors (e.g. timeouts, local validation).
15 def __init__(self, message: str, status_code: int | None = None) -> None: 16 """Create a PaperlessError. 17 18 Args: 19 message: Human-readable error description. 20 status_code: HTTP status code, if applicable. 21 """ 22 super().__init__(message) 23 self.status_code = status_code
Create a PaperlessError.
Arguments:
- message: Human-readable error description.
- status_code: HTTP status code, if applicable.
26class AuthError(PaperlessError): 27 """Raised on 401 or 403 responses. 28 29 Indicates that the API key is missing, invalid, or lacks permission for 30 the requested operation. 31 """
Raised on 401 or 403 responses.
Indicates that the API key is missing, invalid, or lacks permission for the requested operation.
34class NotFoundError(PaperlessError): 35 """Raised on 404 responses or when a name lookup fails."""
Raised on 404 responses or when a name lookup fails.
38class ValidationError(PaperlessError): 39 """Raised on 422 responses or bad input supplied by the caller."""
Raised on 422 responses or bad input supplied by the caller.
42class ServerError(PaperlessError): 43 """Raised on 5xx responses or unrecoverable transport errors."""
Raised on 5xx responses or unrecoverable transport errors.
46class UploadError(PaperlessError): 47 """Raised when file submission or document processing fails. 48 49 Typically raised when paperless-ngx reports a ``FAILURE`` status on the 50 Celery task created by 51 :meth:`~easypaperless.client.PaperlessClient.upload_document`. 52 """
Raised when file submission or document processing fails.
Typically raised when paperless-ngx reports a FAILURE status on the
Celery task created by
~easypaperless.client.PaperlessClient.upload_document().
55class TaskTimeoutError(PaperlessError): 56 """Raised when upload polling exceeds the configured timeout. 57 58 Raised by :meth:`~easypaperless.client.PaperlessClient.upload_document` 59 (with ``wait=True``) when the document processing task does not reach a 60 terminal state within ``poll_timeout`` seconds. 61 """ 62 63 def __init__(self, message: str) -> None: 64 super().__init__(message, status_code=None)
Raised when upload polling exceeds the configured timeout.
Raised by ~easypaperless.client.PaperlessClient.upload_document()
(with wait=True) when the document processing task does not reach a
terminal state within poll_timeout seconds.
67class RetryExhaustedError(PaperlessError): 68 """Raised when all retry attempts are exhausted. 69 70 Attributes: 71 attempts: Total number of attempts made (initial + retries). 72 url: The URL that was requested. 73 """ 74 75 def __init__(self, message: str, attempts: int, url: str) -> None: 76 """Create a RetryExhaustedError. 77 78 Args: 79 message: Human-readable error description. 80 attempts: Total number of attempts made. 81 url: The URL that was requested. 82 """ 83 super().__init__(message, status_code=None) 84 self.attempts = attempts 85 self.url = url
Raised when all retry attempts are exhausted.
Attributes:
- attempts: Total number of attempts made (initial + retries).
- url: The URL that was requested.
75 def __init__(self, message: str, attempts: int, url: str) -> None: 76 """Create a RetryExhaustedError. 77 78 Args: 79 message: Human-readable error description. 80 attempts: Total number of attempts made. 81 url: The URL that was requested. 82 """ 83 super().__init__(message, status_code=None) 84 self.attempts = attempts 85 self.url = url
Create a RetryExhaustedError.
Arguments:
- message: Human-readable error description.
- attempts: Total number of attempts made.
- url: The URL that was requested.