easypaperless.resources

Resource Classes

The following resource classes are _internal classes. Methods can be accessed via the instance of easypaperless.PaperlessClient or easypaperless.SyncPaperlessClient

Example:

async with PaperlessClient(url="http://localhost:8000", api_token="abc") as client: docs = await client.documents.list(max_results=10)

 1"""Resource Classes
 2
 3The following resource classes are _internal classes. Methods can be accessed via the instance of
 4`easypaperless.PaperlessClient` or `easypaperless.SyncPaperlessClient`
 5
 6Example:
 7    async with PaperlessClient(url="http://localhost:8000", api_token="abc") as client:
 8        docs = await client.documents.list(max_results=10)
 9
10"""
11
12# internal comment: the doc string above is also rendered in the pdoc documentation.
13#
14# original was:
15#
16# Public resource classes — for type annotations and IDE support.
17#
18# Re-exports all async and sync resource classes from the internal modules
19# so that pdoc can document them as a full page with all methods.
20#
21# Example:
22#    from easypaperless.resources import DocumentsResource
23
24from easypaperless._internal.resources.correspondents import CorrespondentsResource
25from easypaperless._internal.resources.custom_fields import CustomFieldsResource
26from easypaperless._internal.resources.document_types import DocumentTypesResource
27from easypaperless._internal.resources.documents import DocumentsResource, NotesResource
28from easypaperless._internal.resources.storage_paths import StoragePathsResource
29from easypaperless._internal.resources.tags import TagsResource
30from easypaperless._internal.resources.trash import TrashResource
31from easypaperless._internal.resources.users import UsersResource
32from easypaperless._internal.sync_resources.correspondents import SyncCorrespondentsResource
33from easypaperless._internal.sync_resources.custom_fields import SyncCustomFieldsResource
34from easypaperless._internal.sync_resources.document_types import SyncDocumentTypesResource
35from easypaperless._internal.sync_resources.documents import (
36    SyncDocumentsResource,
37    SyncNotesResource,
38)
39from easypaperless._internal.sync_resources.storage_paths import SyncStoragePathsResource
40from easypaperless._internal.sync_resources.tags import SyncTagsResource
41from easypaperless._internal.sync_resources.trash import SyncTrashResource
42from easypaperless._internal.sync_resources.users import SyncUsersResource
43
44__all__ = [
45    "CorrespondentsResource",
46    "CustomFieldsResource",
47    "DocumentTypesResource",
48    "DocumentsResource",
49    "NotesResource",
50    "StoragePathsResource",
51    "TagsResource",
52    "SyncCorrespondentsResource",
53    "SyncCustomFieldsResource",
54    "SyncDocumentTypesResource",
55    "SyncDocumentsResource",
56    "SyncNotesResource",
57    "SyncStoragePathsResource",
58    "SyncTagsResource",
59    "UsersResource",
60    "SyncUsersResource",
61    "TrashResource",
62    "SyncTrashResource",
63]
class CorrespondentsResource:
 21class CorrespondentsResource:
 22    """Accessor for correspondents: ``client.correspondents``."""
 23
 24    def __init__(self, core: _ClientCore) -> None:
 25        self._core = core
 26
 27    async def list(
 28        self,
 29        *,
 30        ids: List[int] | None = None,
 31        name_contains: str | None = None,
 32        name_exact: str | None = None,
 33        page: int | None = None,
 34        page_size: int | None = None,
 35        ordering: str | None = None,
 36        descending: bool = False,
 37    ) -> PagedResult[Correspondent]:
 38        """Return correspondents defined in paperless-ngx.
 39
 40        When ``page`` is ``None`` (the default), all pages are fetched
 41        automatically and ``next`` / ``previous`` in the result are always
 42        ``None``.  When ``page`` is set, only that page is fetched and
 43        ``next`` / ``previous`` reflect the raw API values.
 44
 45        Args:
 46            ids: Return only correspondents whose ID is in this list.
 47            name_contains: Case-insensitive substring filter on name.
 48            name_exact: Case-insensitive exact match on name.
 49            page: Return only this specific page (1-based).
 50            page_size: Number of results per page.
 51            ordering: Field to sort by.
 52            descending: When ``True``, reverses the sort direction.
 53
 54        Returns:
 55            :class:`~easypaperless.models.paged_result.PagedResult` of
 56            :class:`~easypaperless.models.correspondents.Correspondent` objects.
 57        """
 58        logger.info("Listing correspondents")
 59        params: dict[str, Any] = {}
 60        if ids is not None:
 61            params["id__in"] = ",".join(str(i) for i in ids)
 62        if name_contains is not None:
 63            params["name__icontains"] = name_contains
 64        if name_exact is not None:
 65            params["name__iexact"] = name_exact
 66        if page is not None:
 67            params["page"] = page
 68        if page_size is not None:
 69            params["page_size"] = page_size
 70        if ordering is not None:
 71            params["ordering"] = f"-{ordering}" if descending else ordering
 72        return cast(
 73            PagedResult[Correspondent],
 74            await self._core._list_resource("correspondents", Correspondent, params or None),
 75        )
 76
 77    async def get(self, id: int) -> Correspondent:
 78        """Fetch a single correspondent by its ID.
 79
 80        Args:
 81            id: Numeric correspondent ID.
 82
 83        Returns:
 84            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
 85
 86        Raises:
 87            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
 88        """
 89        logger.info("Getting correspondent id=%d", id)
 90        return cast(
 91            Correspondent, await self._core._get_resource("correspondents", id, Correspondent)
 92        )
 93
 94    async def create(
 95        self,
 96        *,
 97        name: str,
 98        match: str | Unset = UNSET,
 99        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
100        is_insensitive: bool = True,
101        owner: int | None | Unset = UNSET,
102        set_permissions: SetPermissions | None | Unset = UNSET,
103    ) -> Correspondent:
104        """Create a new correspondent.
105
106        Args:
107            name: Correspondent name. Must be unique.
108            match: Auto-matching pattern.
109            matching_algorithm: Controls how ``match`` is applied.
110                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
111                regular-expression matching.
112            is_insensitive: When ``True``, ``match`` is case-insensitive.
113                Defaults to ``True``, matching the paperless-ngx API default.
114            owner: Numeric user ID to assign as owner.
115            set_permissions: Explicit view/change permission sets.
116                Pass ``None`` to create with empty permissions.
117
118        Returns:
119            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
120        """
121        logger.info("Creating correspondent name=%r", name)
122        return cast(
123            Correspondent,
124            await self._core._create_resource(
125                "correspondents",
126                Correspondent,
127                owner=owner,
128                set_permissions=set_permissions,
129                name=name,
130                match=match,
131                matching_algorithm=matching_algorithm,
132                is_insensitive=is_insensitive,
133            ),
134        )
135
136    async def update(
137        self,
138        id: int,
139        *,
140        name: str | Unset = UNSET,
141        match: str | Unset = UNSET,
142        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
143        is_insensitive: bool | Unset = UNSET,
144        owner: int | None | Unset = UNSET,
145        set_permissions: SetPermissions | None | Unset = UNSET,
146    ) -> Correspondent:
147        """Partially update a correspondent (PATCH semantics).
148
149        Args:
150            id: Numeric ID of the correspondent to update.
151            name: Correspondent name.
152            match: Auto-matching pattern.
153            matching_algorithm: Controls how ``match`` is applied.
154                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
155                regular-expression matching.
156            is_insensitive: When ``True``, ``match`` is case-insensitive.
157            owner: Numeric user ID to assign as owner.
158                Pass ``None`` to clear the owner.
159                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
160            set_permissions: Explicit view/change permission sets.
161                Pass ``None`` to clear all permissions (overwrite with empty).
162                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
163
164        Returns:
165            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
166        """
167        logger.info("Updating correspondent id=%d", id)
168        return cast(
169            Correspondent,
170            await self._core._update_resource(
171                "correspondents",
172                id,
173                Correspondent,
174                name=name,
175                match=match,
176                matching_algorithm=matching_algorithm,
177                is_insensitive=is_insensitive,
178                owner=owner,
179                set_permissions=set_permissions,
180            ),
181        )
182
183    async def delete(self, id: int) -> None:
184        """Delete a correspondent.
185
186        Args:
187            id: Numeric ID of the correspondent to delete.
188
189        Raises:
190            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
191        """
192        logger.info("Deleting correspondent id=%d", id)
193        await self._core._delete_resource("correspondents", id)
194
195    async def bulk_delete(self, ids: List[int]) -> None:
196        """Permanently delete multiple correspondents in a single request.
197
198        Args:
199            ids: List of correspondent IDs to delete.
200        """
201        logger.info("Bulk deleting %d correspondents", len(ids))
202        await self._core._bulk_edit_objects("correspondents", ids, "delete")
203
204    async def bulk_set_permissions(
205        self,
206        ids: List[int],
207        *,
208        set_permissions: SetPermissions | Unset = UNSET,
209        owner: int | None | Unset = UNSET,
210        merge: bool = False,
211    ) -> None:
212        """Set permissions and/or owner on multiple correspondents.
213
214        Args:
215            ids: List of correspondent IDs to modify.
216            set_permissions: Explicit view/change permission sets.
217                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
218            owner: Numeric user ID to assign as owner.
219                Pass ``None`` to clear the owner.
220                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
221            merge: When ``True``, new permissions are merged with existing ones.
222        """
223        logger.info("Bulk setting permissions on %d correspondents", len(ids))
224        params: dict[str, Any] = {"merge": merge}
225        if not isinstance(set_permissions, Unset):
226            params["permissions"] = set_permissions.model_dump()
227        if not isinstance(owner, Unset):
228            params["owner"] = owner
229        await self._core._bulk_edit_objects("correspondents", ids, "set_permissions", **params)

Accessor for correspondents: client.correspondents.

CorrespondentsResource(core: easypaperless.client._ClientCore)
24    def __init__(self, core: _ClientCore) -> None:
25        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[Correspondent]:
27    async def list(
28        self,
29        *,
30        ids: List[int] | None = None,
31        name_contains: str | None = None,
32        name_exact: str | None = None,
33        page: int | None = None,
34        page_size: int | None = None,
35        ordering: str | None = None,
36        descending: bool = False,
37    ) -> PagedResult[Correspondent]:
38        """Return correspondents defined in paperless-ngx.
39
40        When ``page`` is ``None`` (the default), all pages are fetched
41        automatically and ``next`` / ``previous`` in the result are always
42        ``None``.  When ``page`` is set, only that page is fetched and
43        ``next`` / ``previous`` reflect the raw API values.
44
45        Args:
46            ids: Return only correspondents whose ID is in this list.
47            name_contains: Case-insensitive substring filter on name.
48            name_exact: Case-insensitive exact match on name.
49            page: Return only this specific page (1-based).
50            page_size: Number of results per page.
51            ordering: Field to sort by.
52            descending: When ``True``, reverses the sort direction.
53
54        Returns:
55            :class:`~easypaperless.models.paged_result.PagedResult` of
56            :class:`~easypaperless.models.correspondents.Correspondent` objects.
57        """
58        logger.info("Listing correspondents")
59        params: dict[str, Any] = {}
60        if ids is not None:
61            params["id__in"] = ",".join(str(i) for i in ids)
62        if name_contains is not None:
63            params["name__icontains"] = name_contains
64        if name_exact is not None:
65            params["name__iexact"] = name_exact
66        if page is not None:
67            params["page"] = page
68        if page_size is not None:
69            params["page_size"] = page_size
70        if ordering is not None:
71            params["ordering"] = f"-{ordering}" if descending else ordering
72        return cast(
73            PagedResult[Correspondent],
74            await self._core._list_resource("correspondents", Correspondent, params or None),
75        )

Return correspondents defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only correspondents whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.correspondents.Correspondent objects.

async def get(self, id: int) -> easypaperless.Correspondent:
77    async def get(self, id: int) -> Correspondent:
78        """Fetch a single correspondent by its ID.
79
80        Args:
81            id: Numeric correspondent ID.
82
83        Returns:
84            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
85
86        Raises:
87            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
88        """
89        logger.info("Getting correspondent id=%d", id)
90        return cast(
91            Correspondent, await self._core._get_resource("correspondents", id, Correspondent)
92        )

Fetch a single correspondent by its ID.

Arguments:
  • id: Numeric correspondent ID.
Returns:

The ~easypaperless.models.correspondents.Correspondent with the given ID.

Raises:
async def create( self, *, name: str, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Correspondent:
 94    async def create(
 95        self,
 96        *,
 97        name: str,
 98        match: str | Unset = UNSET,
 99        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
100        is_insensitive: bool = True,
101        owner: int | None | Unset = UNSET,
102        set_permissions: SetPermissions | None | Unset = UNSET,
103    ) -> Correspondent:
104        """Create a new correspondent.
105
106        Args:
107            name: Correspondent name. Must be unique.
108            match: Auto-matching pattern.
109            matching_algorithm: Controls how ``match`` is applied.
110                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
111                regular-expression matching.
112            is_insensitive: When ``True``, ``match`` is case-insensitive.
113                Defaults to ``True``, matching the paperless-ngx API default.
114            owner: Numeric user ID to assign as owner.
115            set_permissions: Explicit view/change permission sets.
116                Pass ``None`` to create with empty permissions.
117
118        Returns:
119            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
120        """
121        logger.info("Creating correspondent name=%r", name)
122        return cast(
123            Correspondent,
124            await self._core._create_resource(
125                "correspondents",
126                Correspondent,
127                owner=owner,
128                set_permissions=set_permissions,
129                name=name,
130                match=match,
131                matching_algorithm=matching_algorithm,
132                is_insensitive=is_insensitive,
133            ),
134        )

Create a new correspondent.

Arguments:
  • name: Correspondent name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.correspondents.Correspondent.

async def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Correspondent:
136    async def update(
137        self,
138        id: int,
139        *,
140        name: str | Unset = UNSET,
141        match: str | Unset = UNSET,
142        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
143        is_insensitive: bool | Unset = UNSET,
144        owner: int | None | Unset = UNSET,
145        set_permissions: SetPermissions | None | Unset = UNSET,
146    ) -> Correspondent:
147        """Partially update a correspondent (PATCH semantics).
148
149        Args:
150            id: Numeric ID of the correspondent to update.
151            name: Correspondent name.
152            match: Auto-matching pattern.
153            matching_algorithm: Controls how ``match`` is applied.
154                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
155                regular-expression matching.
156            is_insensitive: When ``True``, ``match`` is case-insensitive.
157            owner: Numeric user ID to assign as owner.
158                Pass ``None`` to clear the owner.
159                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
160            set_permissions: Explicit view/change permission sets.
161                Pass ``None`` to clear all permissions (overwrite with empty).
162                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
163
164        Returns:
165            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
166        """
167        logger.info("Updating correspondent id=%d", id)
168        return cast(
169            Correspondent,
170            await self._core._update_resource(
171                "correspondents",
172                id,
173                Correspondent,
174                name=name,
175                match=match,
176                matching_algorithm=matching_algorithm,
177                is_insensitive=is_insensitive,
178                owner=owner,
179                set_permissions=set_permissions,
180            ),
181        )

Partially update a correspondent (PATCH semantics).

Arguments:
  • id: Numeric ID of the correspondent to update.
  • name: Correspondent name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.correspondents.Correspondent.

async def delete(self, id: int) -> None:
183    async def delete(self, id: int) -> None:
184        """Delete a correspondent.
185
186        Args:
187            id: Numeric ID of the correspondent to delete.
188
189        Raises:
190            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
191        """
192        logger.info("Deleting correspondent id=%d", id)
193        await self._core._delete_resource("correspondents", id)

Delete a correspondent.

Arguments:
  • id: Numeric ID of the correspondent to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
195    async def bulk_delete(self, ids: List[int]) -> None:
196        """Permanently delete multiple correspondents in a single request.
197
198        Args:
199            ids: List of correspondent IDs to delete.
200        """
201        logger.info("Bulk deleting %d correspondents", len(ids))
202        await self._core._bulk_edit_objects("correspondents", ids, "delete")

Permanently delete multiple correspondents in a single request.

Arguments:
  • ids: List of correspondent IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
204    async def bulk_set_permissions(
205        self,
206        ids: List[int],
207        *,
208        set_permissions: SetPermissions | Unset = UNSET,
209        owner: int | None | Unset = UNSET,
210        merge: bool = False,
211    ) -> None:
212        """Set permissions and/or owner on multiple correspondents.
213
214        Args:
215            ids: List of correspondent IDs to modify.
216            set_permissions: Explicit view/change permission sets.
217                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
218            owner: Numeric user ID to assign as owner.
219                Pass ``None`` to clear the owner.
220                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
221            merge: When ``True``, new permissions are merged with existing ones.
222        """
223        logger.info("Bulk setting permissions on %d correspondents", len(ids))
224        params: dict[str, Any] = {"merge": merge}
225        if not isinstance(set_permissions, Unset):
226            params["permissions"] = set_permissions.model_dump()
227        if not isinstance(owner, Unset):
228            params["owner"] = owner
229        await self._core._bulk_edit_objects("correspondents", ids, "set_permissions", **params)

Set permissions and/or owner on multiple correspondents.

Arguments:
  • ids: List of correspondent IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class CustomFieldsResource:
 20class CustomFieldsResource:
 21    """Accessor for custom fields: ``client.custom_fields``."""
 22
 23    def __init__(self, core: _ClientCore) -> None:
 24        self._core = core
 25
 26    async def list(
 27        self,
 28        *,
 29        name_contains: str | None = None,
 30        name_exact: str | None = None,
 31        page: int | None = None,
 32        page_size: int | None = None,
 33        ordering: str | None = None,
 34        descending: bool = False,
 35    ) -> PagedResult[CustomField]:
 36        """Return all custom fields defined in paperless-ngx.
 37
 38        When ``page`` is ``None`` (the default), all pages are fetched
 39        automatically and ``next`` / ``previous`` in the result are always
 40        ``None``.  When ``page`` is set, only that page is fetched and
 41        ``next`` / ``previous`` reflect the raw API values.
 42
 43        Args:
 44            name_contains: Case-insensitive substring filter on name.
 45            name_exact: Case-insensitive exact match on name.
 46            page: Return only this specific page (1-based).
 47            page_size: Number of results per page.
 48            ordering: Field to sort by.
 49            descending: When ``True``, reverses the sort direction.
 50
 51        Returns:
 52            :class:`~easypaperless.models.paged_result.PagedResult` of
 53            :class:`~easypaperless.models.custom_fields.CustomField` objects.
 54        """
 55        logger.info("Listing custom fields")
 56        params: dict[str, Any] = {}
 57        if name_contains is not None:
 58            params["name__icontains"] = name_contains
 59        if name_exact is not None:
 60            params["name__iexact"] = name_exact
 61        if page is not None:
 62            params["page"] = page
 63        if page_size is not None:
 64            params["page_size"] = page_size
 65        if ordering is not None:
 66            params["ordering"] = f"-{ordering}" if descending else ordering
 67        return cast(
 68            PagedResult[CustomField],
 69            await self._core._list_resource("custom_fields", CustomField, params or None),
 70        )
 71
 72    async def get(self, id: int) -> CustomField:
 73        """Fetch a single custom field by its ID.
 74
 75        Args:
 76            id: Numeric custom-field ID.
 77
 78        Returns:
 79            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
 80
 81        Raises:
 82            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
 83        """
 84        logger.info("Getting custom field id=%d", id)
 85        return cast(CustomField, await self._core._get_resource("custom_fields", id, CustomField))
 86
 87    async def create(
 88        self,
 89        *,
 90        name: str,
 91        data_type: str,
 92        extra_data: Any | None = None,
 93        owner: int | None | Unset = UNSET,
 94        set_permissions: SetPermissions | None | Unset = UNSET,
 95    ) -> CustomField:
 96        """Create a new custom field.
 97
 98        Args:
 99            name: Field name shown in the UI. Must be unique.
100            data_type: Value type. One of ``"string"``, ``"boolean"``,
101                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
102                ``"url"``, ``"documentlink"``, ``"select"``.
103            extra_data: Additional configuration for the field type.
104            owner: Numeric user ID to assign as owner.
105            set_permissions: Explicit view/change permission sets.
106                Pass ``None`` to create with empty permissions.
107
108        Returns:
109            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
110        """
111        logger.info("Creating custom field name=%r data_type=%r", name, data_type)
112        return cast(
113            CustomField,
114            await self._core._create_resource(
115                "custom_fields",
116                CustomField,
117                owner=owner,
118                set_permissions=set_permissions,
119                name=name,
120                data_type=data_type,
121                extra_data=extra_data,
122            ),
123        )
124
125    async def update(
126        self,
127        id: int,
128        *,
129        name: str | Unset = UNSET,
130        data_type: str | Unset = UNSET,
131        extra_data: Any | None | Unset = UNSET,
132        owner: int | None | Unset = UNSET,
133        set_permissions: SetPermissions | None | Unset = UNSET,
134    ) -> CustomField:
135        """Partially update a custom field (PATCH semantics).
136
137        Args:
138            id: Numeric ID of the custom field to update.
139            name: Field name shown in the UI.
140            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142            extra_data: Additional configuration for the field type.
143            owner: Numeric user ID to assign as owner.
144                Pass ``None`` to clear the owner.
145                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
146            set_permissions: Explicit view/change permission sets.
147                Pass ``None`` to clear all permissions (overwrite with empty).
148                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
149
150        Returns:
151            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
152        """
153        logger.info("Updating custom field id=%d", id)
154        return cast(
155            CustomField,
156            await self._core._update_resource(
157                "custom_fields",
158                id,
159                CustomField,
160                name=name,
161                data_type=data_type,
162                extra_data=extra_data,
163                owner=owner,
164                set_permissions=set_permissions,
165            ),
166        )
167
168    async def delete(self, id: int) -> None:
169        """Delete a custom field.
170
171        Args:
172            id: Numeric ID of the custom field to delete.
173
174        Raises:
175            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
176        """
177        logger.info("Deleting custom field id=%d", id)
178        await self._core._delete_resource("custom_fields", id)

Accessor for custom fields: client.custom_fields.

CustomFieldsResource(core: easypaperless.client._ClientCore)
23    def __init__(self, core: _ClientCore) -> None:
24        self._core = core
async def list( self, *, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[CustomField]:
26    async def list(
27        self,
28        *,
29        name_contains: str | None = None,
30        name_exact: str | None = None,
31        page: int | None = None,
32        page_size: int | None = None,
33        ordering: str | None = None,
34        descending: bool = False,
35    ) -> PagedResult[CustomField]:
36        """Return all custom fields defined in paperless-ngx.
37
38        When ``page`` is ``None`` (the default), all pages are fetched
39        automatically and ``next`` / ``previous`` in the result are always
40        ``None``.  When ``page`` is set, only that page is fetched and
41        ``next`` / ``previous`` reflect the raw API values.
42
43        Args:
44            name_contains: Case-insensitive substring filter on name.
45            name_exact: Case-insensitive exact match on name.
46            page: Return only this specific page (1-based).
47            page_size: Number of results per page.
48            ordering: Field to sort by.
49            descending: When ``True``, reverses the sort direction.
50
51        Returns:
52            :class:`~easypaperless.models.paged_result.PagedResult` of
53            :class:`~easypaperless.models.custom_fields.CustomField` objects.
54        """
55        logger.info("Listing custom fields")
56        params: dict[str, Any] = {}
57        if name_contains is not None:
58            params["name__icontains"] = name_contains
59        if name_exact is not None:
60            params["name__iexact"] = name_exact
61        if page is not None:
62            params["page"] = page
63        if page_size is not None:
64            params["page_size"] = page_size
65        if ordering is not None:
66            params["ordering"] = f"-{ordering}" if descending else ordering
67        return cast(
68            PagedResult[CustomField],
69            await self._core._list_resource("custom_fields", CustomField, params or None),
70        )

Return all custom fields defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.custom_fields.CustomField objects.

async def get(self, id: int) -> easypaperless.CustomField:
72    async def get(self, id: int) -> CustomField:
73        """Fetch a single custom field by its ID.
74
75        Args:
76            id: Numeric custom-field ID.
77
78        Returns:
79            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
80
81        Raises:
82            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
83        """
84        logger.info("Getting custom field id=%d", id)
85        return cast(CustomField, await self._core._get_resource("custom_fields", id, CustomField))

Fetch a single custom field by its ID.

Arguments:
  • id: Numeric custom-field ID.
Returns:

The ~easypaperless.models.custom_fields.CustomField with the given ID.

Raises:
async def create( self, *, name: str, data_type: str, extra_data: typing.Any | None = None, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.CustomField:
 87    async def create(
 88        self,
 89        *,
 90        name: str,
 91        data_type: str,
 92        extra_data: Any | None = None,
 93        owner: int | None | Unset = UNSET,
 94        set_permissions: SetPermissions | None | Unset = UNSET,
 95    ) -> CustomField:
 96        """Create a new custom field.
 97
 98        Args:
 99            name: Field name shown in the UI. Must be unique.
100            data_type: Value type. One of ``"string"``, ``"boolean"``,
101                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
102                ``"url"``, ``"documentlink"``, ``"select"``.
103            extra_data: Additional configuration for the field type.
104            owner: Numeric user ID to assign as owner.
105            set_permissions: Explicit view/change permission sets.
106                Pass ``None`` to create with empty permissions.
107
108        Returns:
109            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
110        """
111        logger.info("Creating custom field name=%r data_type=%r", name, data_type)
112        return cast(
113            CustomField,
114            await self._core._create_resource(
115                "custom_fields",
116                CustomField,
117                owner=owner,
118                set_permissions=set_permissions,
119                name=name,
120                data_type=data_type,
121                extra_data=extra_data,
122            ),
123        )

Create a new custom field.

Arguments:
  • name: Field name shown in the UI. Must be unique.
  • data_type: Value type. One of "string", "boolean", "integer", "float", "monetary", "date", "url", "documentlink", "select".
  • extra_data: Additional configuration for the field type.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.custom_fields.CustomField.

async def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, data_type: str | easypaperless.Unset = UNSET, extra_data: typing.Any | None | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.CustomField:
125    async def update(
126        self,
127        id: int,
128        *,
129        name: str | Unset = UNSET,
130        data_type: str | Unset = UNSET,
131        extra_data: Any | None | Unset = UNSET,
132        owner: int | None | Unset = UNSET,
133        set_permissions: SetPermissions | None | Unset = UNSET,
134    ) -> CustomField:
135        """Partially update a custom field (PATCH semantics).
136
137        Args:
138            id: Numeric ID of the custom field to update.
139            name: Field name shown in the UI.
140            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142            extra_data: Additional configuration for the field type.
143            owner: Numeric user ID to assign as owner.
144                Pass ``None`` to clear the owner.
145                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
146            set_permissions: Explicit view/change permission sets.
147                Pass ``None`` to clear all permissions (overwrite with empty).
148                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
149
150        Returns:
151            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
152        """
153        logger.info("Updating custom field id=%d", id)
154        return cast(
155            CustomField,
156            await self._core._update_resource(
157                "custom_fields",
158                id,
159                CustomField,
160                name=name,
161                data_type=data_type,
162                extra_data=extra_data,
163                owner=owner,
164                set_permissions=set_permissions,
165            ),
166        )

Partially update a custom field (PATCH semantics).

Arguments:
  • id: Numeric ID of the custom field to update.
  • name: Field name shown in the UI.
  • data_type: Value type (e.g. "string", "boolean", "integer"). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • extra_data: Additional configuration for the field type.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.custom_fields.CustomField.

async def delete(self, id: int) -> None:
168    async def delete(self, id: int) -> None:
169        """Delete a custom field.
170
171        Args:
172            id: Numeric ID of the custom field to delete.
173
174        Raises:
175            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
176        """
177        logger.info("Deleting custom field id=%d", id)
178        await self._core._delete_resource("custom_fields", id)

Delete a custom field.

Arguments:
  • id: Numeric ID of the custom field to delete.
Raises:
class DocumentTypesResource:
 21class DocumentTypesResource:
 22    """Accessor for document types: ``client.document_types``."""
 23
 24    def __init__(self, core: _ClientCore) -> None:
 25        self._core = core
 26
 27    async def list(
 28        self,
 29        *,
 30        ids: List[int] | None = None,
 31        name_contains: str | None = None,
 32        name_exact: str | None = None,
 33        page: int | None = None,
 34        page_size: int | None = None,
 35        ordering: str | None = None,
 36        descending: bool = False,
 37    ) -> PagedResult[DocumentType]:
 38        """Return document types defined in paperless-ngx.
 39
 40        When ``page`` is ``None`` (the default), all pages are fetched
 41        automatically and ``next`` / ``previous`` in the result are always
 42        ``None``.  When ``page`` is set, only that page is fetched and
 43        ``next`` / ``previous`` reflect the raw API values.
 44
 45        Args:
 46            ids: Return only document types whose ID is in this list.
 47            name_contains: Case-insensitive substring filter on name.
 48            name_exact: Case-insensitive exact match on name.
 49            page: Return only this specific page (1-based).
 50            page_size: Number of results per page.
 51            ordering: Field to sort by.
 52            descending: When ``True``, reverses the sort direction.
 53
 54        Returns:
 55            :class:`~easypaperless.models.paged_result.PagedResult` of
 56            :class:`~easypaperless.models.document_types.DocumentType` objects.
 57        """
 58        logger.info("Listing document types")
 59        params: dict[str, Any] = {}
 60        if ids is not None:
 61            params["id__in"] = ",".join(str(i) for i in ids)
 62        if name_contains is not None:
 63            params["name__icontains"] = name_contains
 64        if name_exact is not None:
 65            params["name__iexact"] = name_exact
 66        if page is not None:
 67            params["page"] = page
 68        if page_size is not None:
 69            params["page_size"] = page_size
 70        if ordering is not None:
 71            params["ordering"] = f"-{ordering}" if descending else ordering
 72        return cast(
 73            PagedResult[DocumentType],
 74            await self._core._list_resource("document_types", DocumentType, params or None),
 75        )
 76
 77    async def get(self, id: int) -> DocumentType:
 78        """Fetch a single document type by its ID.
 79
 80        Args:
 81            id: Numeric document-type ID.
 82
 83        Returns:
 84            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
 85
 86        Raises:
 87            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
 88        """
 89        logger.info("Getting document type id=%d", id)
 90        return cast(
 91            DocumentType, await self._core._get_resource("document_types", id, DocumentType)
 92        )
 93
 94    async def create(
 95        self,
 96        *,
 97        name: str,
 98        match: str | Unset = UNSET,
 99        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
100        is_insensitive: bool = True,
101        owner: int | None | Unset = UNSET,
102        set_permissions: SetPermissions | None | Unset = UNSET,
103    ) -> DocumentType:
104        """Create a new document type.
105
106        Args:
107            name: Document-type name. Must be unique.
108            match: Auto-matching pattern.
109            matching_algorithm: Controls how ``match`` is applied.
110                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
111                regular-expression matching.
112            is_insensitive: When ``True``, ``match`` is case-insensitive.
113                Defaults to ``True``, matching the paperless-ngx API default.
114            owner: Numeric user ID to assign as owner.
115            set_permissions: Explicit view/change permission sets.
116                Pass ``None`` to create with empty permissions.
117
118        Returns:
119            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
120        """
121        logger.info("Creating document type name=%r", name)
122        return cast(
123            DocumentType,
124            await self._core._create_resource(
125                "document_types",
126                DocumentType,
127                owner=owner,
128                set_permissions=set_permissions,
129                name=name,
130                match=match,
131                matching_algorithm=matching_algorithm,
132                is_insensitive=is_insensitive,
133            ),
134        )
135
136    async def update(
137        self,
138        id: int,
139        *,
140        name: str | Unset = UNSET,
141        match: str | Unset = UNSET,
142        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
143        is_insensitive: bool | Unset = UNSET,
144        owner: int | None | Unset = UNSET,
145        set_permissions: SetPermissions | None | Unset = UNSET,
146    ) -> DocumentType:
147        """Partially update a document type (PATCH semantics).
148
149        Args:
150            id: Numeric ID of the document type to update.
151            name: Document-type name.
152            match: Auto-matching pattern.
153            matching_algorithm: Controls how ``match`` is applied.
154                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
155                regular-expression matching.
156            is_insensitive: When ``True``, ``match`` is case-insensitive.
157            owner: Numeric user ID to assign as owner.
158                Pass ``None`` to clear the owner.
159                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
160            set_permissions: Explicit view/change permission sets.
161                Pass ``None`` to clear all permissions (overwrite with empty).
162                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
163
164        Returns:
165            The updated :class:`~easypaperless.models.document_types.DocumentType`.
166        """
167        logger.info("Updating document type id=%d", id)
168        return cast(
169            DocumentType,
170            await self._core._update_resource(
171                "document_types",
172                id,
173                DocumentType,
174                name=name,
175                match=match,
176                matching_algorithm=matching_algorithm,
177                is_insensitive=is_insensitive,
178                owner=owner,
179                set_permissions=set_permissions,
180            ),
181        )
182
183    async def delete(self, id: int) -> None:
184        """Delete a document type.
185
186        Args:
187            id: Numeric ID of the document type to delete.
188
189        Raises:
190            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
191        """
192        logger.info("Deleting document type id=%d", id)
193        await self._core._delete_resource("document_types", id)
194
195    async def bulk_delete(self, ids: List[int]) -> None:
196        """Permanently delete multiple document types in a single request.
197
198        Args:
199            ids: List of document type IDs to delete.
200        """
201        logger.info("Bulk deleting %d document types", len(ids))
202        await self._core._bulk_edit_objects("document_types", ids, "delete")
203
204    async def bulk_set_permissions(
205        self,
206        ids: List[int],
207        *,
208        set_permissions: SetPermissions | Unset = UNSET,
209        owner: int | None | Unset = UNSET,
210        merge: bool = False,
211    ) -> None:
212        """Set permissions and/or owner on multiple document types.
213
214        Args:
215            ids: List of document type IDs to modify.
216            set_permissions: Explicit view/change permission sets.
217                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
218            owner: Numeric user ID to assign as owner.
219                Pass ``None`` to clear the owner.
220                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
221            merge: When ``True``, new permissions are merged with existing ones.
222        """
223        logger.info("Bulk setting permissions on %d document types", len(ids))
224        params: dict[str, Any] = {"merge": merge}
225        if not isinstance(set_permissions, Unset):
226            params["permissions"] = set_permissions.model_dump()
227        if not isinstance(owner, Unset):
228            params["owner"] = owner
229        await self._core._bulk_edit_objects("document_types", ids, "set_permissions", **params)

Accessor for document types: client.document_types.

DocumentTypesResource(core: easypaperless.client._ClientCore)
24    def __init__(self, core: _ClientCore) -> None:
25        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[DocumentType]:
27    async def list(
28        self,
29        *,
30        ids: List[int] | None = None,
31        name_contains: str | None = None,
32        name_exact: str | None = None,
33        page: int | None = None,
34        page_size: int | None = None,
35        ordering: str | None = None,
36        descending: bool = False,
37    ) -> PagedResult[DocumentType]:
38        """Return document types defined in paperless-ngx.
39
40        When ``page`` is ``None`` (the default), all pages are fetched
41        automatically and ``next`` / ``previous`` in the result are always
42        ``None``.  When ``page`` is set, only that page is fetched and
43        ``next`` / ``previous`` reflect the raw API values.
44
45        Args:
46            ids: Return only document types whose ID is in this list.
47            name_contains: Case-insensitive substring filter on name.
48            name_exact: Case-insensitive exact match on name.
49            page: Return only this specific page (1-based).
50            page_size: Number of results per page.
51            ordering: Field to sort by.
52            descending: When ``True``, reverses the sort direction.
53
54        Returns:
55            :class:`~easypaperless.models.paged_result.PagedResult` of
56            :class:`~easypaperless.models.document_types.DocumentType` objects.
57        """
58        logger.info("Listing document types")
59        params: dict[str, Any] = {}
60        if ids is not None:
61            params["id__in"] = ",".join(str(i) for i in ids)
62        if name_contains is not None:
63            params["name__icontains"] = name_contains
64        if name_exact is not None:
65            params["name__iexact"] = name_exact
66        if page is not None:
67            params["page"] = page
68        if page_size is not None:
69            params["page_size"] = page_size
70        if ordering is not None:
71            params["ordering"] = f"-{ordering}" if descending else ordering
72        return cast(
73            PagedResult[DocumentType],
74            await self._core._list_resource("document_types", DocumentType, params or None),
75        )

Return document types defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only document types whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.document_types.DocumentType objects.

async def get(self, id: int) -> easypaperless.DocumentType:
77    async def get(self, id: int) -> DocumentType:
78        """Fetch a single document type by its ID.
79
80        Args:
81            id: Numeric document-type ID.
82
83        Returns:
84            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
85
86        Raises:
87            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
88        """
89        logger.info("Getting document type id=%d", id)
90        return cast(
91            DocumentType, await self._core._get_resource("document_types", id, DocumentType)
92        )

Fetch a single document type by its ID.

Arguments:
  • id: Numeric document-type ID.
Returns:

The ~easypaperless.models.document_types.DocumentType with the given ID.

Raises:
async def create( self, *, name: str, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.DocumentType:
 94    async def create(
 95        self,
 96        *,
 97        name: str,
 98        match: str | Unset = UNSET,
 99        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
100        is_insensitive: bool = True,
101        owner: int | None | Unset = UNSET,
102        set_permissions: SetPermissions | None | Unset = UNSET,
103    ) -> DocumentType:
104        """Create a new document type.
105
106        Args:
107            name: Document-type name. Must be unique.
108            match: Auto-matching pattern.
109            matching_algorithm: Controls how ``match`` is applied.
110                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
111                regular-expression matching.
112            is_insensitive: When ``True``, ``match`` is case-insensitive.
113                Defaults to ``True``, matching the paperless-ngx API default.
114            owner: Numeric user ID to assign as owner.
115            set_permissions: Explicit view/change permission sets.
116                Pass ``None`` to create with empty permissions.
117
118        Returns:
119            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
120        """
121        logger.info("Creating document type name=%r", name)
122        return cast(
123            DocumentType,
124            await self._core._create_resource(
125                "document_types",
126                DocumentType,
127                owner=owner,
128                set_permissions=set_permissions,
129                name=name,
130                match=match,
131                matching_algorithm=matching_algorithm,
132                is_insensitive=is_insensitive,
133            ),
134        )

Create a new document type.

Arguments:
  • name: Document-type name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.document_types.DocumentType.

async def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.DocumentType:
136    async def update(
137        self,
138        id: int,
139        *,
140        name: str | Unset = UNSET,
141        match: str | Unset = UNSET,
142        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
143        is_insensitive: bool | Unset = UNSET,
144        owner: int | None | Unset = UNSET,
145        set_permissions: SetPermissions | None | Unset = UNSET,
146    ) -> DocumentType:
147        """Partially update a document type (PATCH semantics).
148
149        Args:
150            id: Numeric ID of the document type to update.
151            name: Document-type name.
152            match: Auto-matching pattern.
153            matching_algorithm: Controls how ``match`` is applied.
154                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
155                regular-expression matching.
156            is_insensitive: When ``True``, ``match`` is case-insensitive.
157            owner: Numeric user ID to assign as owner.
158                Pass ``None`` to clear the owner.
159                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
160            set_permissions: Explicit view/change permission sets.
161                Pass ``None`` to clear all permissions (overwrite with empty).
162                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
163
164        Returns:
165            The updated :class:`~easypaperless.models.document_types.DocumentType`.
166        """
167        logger.info("Updating document type id=%d", id)
168        return cast(
169            DocumentType,
170            await self._core._update_resource(
171                "document_types",
172                id,
173                DocumentType,
174                name=name,
175                match=match,
176                matching_algorithm=matching_algorithm,
177                is_insensitive=is_insensitive,
178                owner=owner,
179                set_permissions=set_permissions,
180            ),
181        )

Partially update a document type (PATCH semantics).

Arguments:
  • id: Numeric ID of the document type to update.
  • name: Document-type name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.document_types.DocumentType.

async def delete(self, id: int) -> None:
183    async def delete(self, id: int) -> None:
184        """Delete a document type.
185
186        Args:
187            id: Numeric ID of the document type to delete.
188
189        Raises:
190            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
191        """
192        logger.info("Deleting document type id=%d", id)
193        await self._core._delete_resource("document_types", id)

Delete a document type.

Arguments:
  • id: Numeric ID of the document type to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
195    async def bulk_delete(self, ids: List[int]) -> None:
196        """Permanently delete multiple document types in a single request.
197
198        Args:
199            ids: List of document type IDs to delete.
200        """
201        logger.info("Bulk deleting %d document types", len(ids))
202        await self._core._bulk_edit_objects("document_types", ids, "delete")

Permanently delete multiple document types in a single request.

Arguments:
  • ids: List of document type IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
204    async def bulk_set_permissions(
205        self,
206        ids: List[int],
207        *,
208        set_permissions: SetPermissions | Unset = UNSET,
209        owner: int | None | Unset = UNSET,
210        merge: bool = False,
211    ) -> None:
212        """Set permissions and/or owner on multiple document types.
213
214        Args:
215            ids: List of document type IDs to modify.
216            set_permissions: Explicit view/change permission sets.
217                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
218            owner: Numeric user ID to assign as owner.
219                Pass ``None`` to clear the owner.
220                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
221            merge: When ``True``, new permissions are merged with existing ones.
222        """
223        logger.info("Bulk setting permissions on %d document types", len(ids))
224        params: dict[str, Any] = {"merge": merge}
225        if not isinstance(set_permissions, Unset):
226            params["permissions"] = set_permissions.model_dump()
227        if not isinstance(owner, Unset):
228            params["owner"] = owner
229        await self._core._bulk_edit_objects("document_types", ids, "set_permissions", **params)

Set permissions and/or owner on multiple document types.

Arguments:
  • ids: List of document type IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class DocumentsResource:
 176class DocumentsResource:
 177    """Accessor for documents: ``client.documents``."""
 178
 179    def __init__(self, core: _ClientCore) -> None:
 180        self._core = core
 181        self.notes = NotesResource(core)
 182
 183    async def history(
 184        self,
 185        document_id: int,
 186        *,
 187        page: int | None = None,
 188        page_size: int | None = None,
 189    ) -> PagedResult[AuditLogEntry]:
 190        """Fetch the audit log for a document.
 191
 192        The paperless-ngx ``/api/documents/{id}/history/`` endpoint returns a
 193        plain JSON array rather than a paginated envelope.  This method wraps
 194        the response into a :class:`~easypaperless.models.paged_result.PagedResult`
 195        so callers always receive a consistent return type.
 196
 197        Args:
 198            document_id: Numeric ID of the document whose history to retrieve.
 199            page: Forwarded to the API as a query parameter when provided.
 200                Effect depends on the paperless-ngx version; the server may
 201                ignore this parameter.
 202            page_size: Forwarded to the API as a query parameter when provided.
 203
 204        Returns:
 205            :class:`~easypaperless.models.paged_result.PagedResult` of
 206            :class:`~easypaperless.models.documents.AuditLogEntry` objects,
 207            ordered by timestamp descending.
 208
 209        Raises:
 210            ~easypaperless.exceptions.NotFoundError: If no document exists
 211                with that ID.
 212        """
 213        logger.info("Fetching history for document id=%d", document_id)
 214        path = f"/documents/{document_id}/history/"
 215        params: dict[str, Any] = {}
 216        if page is not None:
 217            params["page"] = page
 218        if page_size is not None:
 219            params["page_size"] = page_size
 220
 221        resp = await self._core._session.get(path, params=params or None)
 222        data = resp.json()
 223
 224        if isinstance(data, list):
 225            entries = [AuditLogEntry.model_validate(item) for item in data]
 226            entry_ids: list[int] = [e.id for e in entries]
 227            return PagedResult(
 228                count=len(entries),
 229                next=None,
 230                previous=None,
 231                all=entry_ids if entry_ids else None,
 232                results=entries,
 233            )
 234
 235        # Forward-compatible: handle a paginated envelope if the API ever adds one.
 236        items: list[Any] = list(data.get("results", []))
 237        count: int = data.get("count", 0)
 238        all_ids: list[int] | None = data.get("all")
 239        return PagedResult(
 240            count=count,
 241            next=data.get("next"),
 242            previous=data.get("previous"),
 243            all=all_ids,
 244            results=[AuditLogEntry.model_validate(item) for item in items],
 245        )
 246
 247    @staticmethod
 248    def _format_date_value(value: date | datetime | str) -> str:
 249        if isinstance(value, datetime):
 250            return value.isoformat()
 251        if isinstance(value, date):
 252            return value.isoformat()
 253        return value
 254
 255    @staticmethod
 256    def _is_datetime(value: date | datetime | str) -> bool:
 257        if isinstance(value, datetime):
 258            return True
 259        if isinstance(value, str):
 260            return bool(_DATETIME_STR_RE.match(value))
 261        return False
 262
 263    async def get(self, id: int, *, include_metadata: bool = False) -> Document:
 264        """Fetch a single document by its ID.
 265
 266        Args:
 267            id: Numeric paperless-ngx document ID.
 268            include_metadata: When ``True``, the extended file-level metadata
 269                is fetched concurrently and attached to the document.
 270                Default: ``False``.
 271
 272        Returns:
 273            The :class:`~easypaperless.models.documents.Document` with the
 274            given ID.
 275
 276        Raises:
 277            ~easypaperless.exceptions.NotFoundError: If no document exists
 278                with that ID.
 279        """
 280        logger.info("Getting document id=%d", id)
 281        if include_metadata:
 282            doc_resp, meta_resp = await asyncio.gather(
 283                self._core._session.get(f"/documents/{id}/"),
 284                self._core._session.get(f"/documents/{id}/metadata/"),
 285            )
 286            data = doc_resp.json()
 287            data["metadata"] = meta_resp.json()
 288        else:
 289            resp = await self._core._session.get(f"/documents/{id}/")
 290            data = resp.json()
 291        return Document.model_validate(data)
 292
 293    async def get_metadata(self, id: int) -> DocumentMetadata:
 294        """Fetch the extended file-level metadata for a document.
 295
 296        Args:
 297            id: Numeric paperless-ngx document ID.
 298
 299        Returns:
 300            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
 301
 302        Raises:
 303            ~easypaperless.exceptions.NotFoundError: If no document exists
 304                with that ID.
 305        """
 306        logger.info("Getting metadata for document id=%d", id)
 307        resp = await self._core._session.get(f"/documents/{id}/metadata/")
 308        return DocumentMetadata.model_validate(resp.json())
 309
 310    async def list(
 311        self,
 312        *,
 313        search: str | None = None,
 314        search_mode: str = "title_or_content",
 315        ids: List[int] | None = None,
 316        tags: List[int | str] | None = None,
 317        any_tags: List[int | str] | None = None,
 318        exclude_tags: List[int | str] | None = None,
 319        correspondent: int | str | None | Unset = UNSET,
 320        any_correspondent: List[int | str] | None = None,
 321        exclude_correspondents: List[int | str] | None = None,
 322        document_type: int | str | None | Unset = UNSET,
 323        document_type_name_contains: str | None = None,
 324        document_type_name_exact: str | None = None,
 325        any_document_type: List[int | str] | None = None,
 326        exclude_document_types: List[int | str] | None = None,
 327        storage_path: int | str | None | Unset = UNSET,
 328        any_storage_paths: List[int | str] | None = None,
 329        exclude_storage_paths: List[int | str] | None = None,
 330        owner: int | None | Unset = UNSET,
 331        exclude_owners: List[int] | None = None,
 332        custom_fields: List[int | str] | None = None,
 333        any_custom_fields: List[int | str] | None = None,
 334        exclude_custom_fields: List[int | str] | None = None,
 335        custom_field_query: List[Any] | None = None,
 336        archive_serial_number: int | None | Unset = UNSET,
 337        archive_serial_number_from: int | None = None,
 338        archive_serial_number_till: int | None = None,
 339        created_after: date | str | None = None,
 340        created_before: date | str | None = None,
 341        added_after: date | datetime | str | None = None,
 342        added_from: date | datetime | str | None = None,
 343        added_before: date | datetime | str | None = None,
 344        added_until: date | datetime | str | None = None,
 345        modified_after: date | datetime | str | None = None,
 346        modified_from: date | datetime | str | None = None,
 347        modified_before: date | datetime | str | None = None,
 348        modified_until: date | datetime | str | None = None,
 349        checksum: str | None = None,
 350        page_size: int = 25,
 351        page: int | None = None,
 352        ordering: str | None = None,
 353        descending: bool = False,
 354        max_results: int | None = None,
 355        on_page: Callable[[int, int | None], None] | None = None,
 356    ) -> PagedResult[Document]:
 357        """Return a filtered list of documents.
 358
 359        All tag, correspondent, document-type, storage-path, and custom-field
 360        parameters accept either integer IDs or string names.
 361
 362        When ``page`` is ``None`` (the default), all pages are fetched
 363        automatically and ``next`` / ``previous`` in the returned
 364        :class:`~easypaperless.models.paged_result.PagedResult` are always
 365        ``None`` — even if ``max_results`` truncates the final result set.
 366        ``count`` always reflects the server total, not the truncated length.
 367        When ``page`` is set to a specific integer, only that one page is
 368        fetched and ``next`` / ``previous`` contain the raw API values.
 369
 370        Args:
 371            search: Search string.  Behaviour depends on ``search_mode``.
 372            search_mode: How ``search`` is applied.  One of:
 373                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
 374                ``"original_filename"``.
 375            ids: Return only documents whose ID is in this list.
 376            tags: Documents must have **all** of these tags (AND semantics).
 377            any_tags: Documents must have **at least one** of these tags.
 378            exclude_tags: Documents must have **none** of these tags.
 379            correspondent: Filter to documents assigned to this correspondent.
 380                Pass ``None`` to return only documents with no correspondent set.
 381            any_correspondent: Filter to documents assigned to any of these.
 382            exclude_correspondents: Exclude documents assigned to any of these.
 383            document_type: Filter to documents of exactly this type.
 384                Pass ``None`` to return only documents with no document type set.
 385            document_type_name_contains: Case-insensitive substring filter on document type name.
 386            document_type_name_exact: Case-insensitive exact match on document type name.
 387            any_document_type: Filter to documents whose type is any of these.
 388            exclude_document_types: Exclude documents whose type is any of these.
 389            storage_path: Filter to documents assigned to this storage path.
 390                Pass ``None`` to return only documents with no storage path set.
 391            any_storage_paths: Filter to documents assigned to any of these paths.
 392            exclude_storage_paths: Exclude documents assigned to any of these paths.
 393            owner: Filter to documents owned by this user ID.
 394                Pass ``None`` to return only documents with no owner set.
 395            exclude_owners: Exclude documents owned by any of these user IDs.
 396            custom_fields: Documents must have **all** of these custom fields set.
 397            any_custom_fields: Documents must have **at least one** of these fields.
 398            exclude_custom_fields: Documents must have **none** of these fields.
 399            custom_field_query: Filter documents by custom field values using a nested
 400                query structure. See the `paperless-ngx API docs
 401                <https://docs.paperless-ngx.com/api/#filtering-by-custom-fields>`_ for
 402                the query format.
 403            archive_serial_number: Filter by exact archive serial number.
 404                Pass ``None`` to return only documents with no ASN set.
 405            archive_serial_number_from: Filter by ASN >= this value.
 406            archive_serial_number_till: Filter by ASN <= this value.
 407            created_after: Only documents created after this date.
 408                String input must be ISO-8601: ``"YYYY-MM-DD"``.
 409            created_before: Only documents created before this date.
 410                String input must be ISO-8601: ``"YYYY-MM-DD"``.
 411            added_after: Only documents added after this date/time.
 412                String input must be ISO-8601: ``"YYYY-MM-DD"`` for date precision or
 413                ``"YYYY-MM-DDTHH:MM:SS"`` for datetime precision.
 414            added_from: Only documents added on or after this date/time.
 415                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
 416            added_before: Only documents added before this date/time.
 417                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
 418            added_until: Only documents added on or before this date/time.
 419                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
 420            modified_after: Only documents modified after this date/time.
 421                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
 422            modified_from: Only documents modified on or after this date/time.
 423                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
 424            modified_before: Only documents modified before this date/time.
 425                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
 426            modified_until: Only documents modified on or before this date/time.
 427                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
 428            checksum: MD5 checksum of the original file (exact match).
 429            page_size: Number of results per API page.  Default: ``25``.
 430            page: Return only this specific page (1-based).
 431            ordering: Field name to sort by.
 432            descending: When ``True``, reverses the sort direction.
 433            max_results: Stop after collecting this many documents.
 434            on_page: Callback invoked after each page fetch.
 435
 436        Returns:
 437            :class:`~easypaperless.models.paged_result.PagedResult` of
 438            :class:`~easypaperless.models.documents.Document` objects.
 439        """
 440        logger.info("Listing documents")
 441        resolver = self._core._resolver
 442        params: dict[str, Any] = {"page_size": page_size}
 443
 444        if search is not None:
 445            api_param = _SEARCH_MODE_MAP.get(search_mode, "search")
 446            params[api_param] = search
 447
 448        if ids is not None:
 449            params["id__in"] = ",".join(str(i) for i in ids)
 450
 451        if tags is not None:
 452            resolved = await resolver.resolve_list("tags", tags)
 453            params["tags__id__all"] = ",".join(str(t) for t in resolved)
 454
 455        if any_tags is not None:
 456            resolved = await resolver.resolve_list("tags", any_tags)
 457            params["tags__id__in"] = ",".join(str(t) for t in resolved)
 458
 459        if exclude_tags is not None:
 460            resolved = await resolver.resolve_list("tags", exclude_tags)
 461            params["tags__id__none"] = ",".join(str(t) for t in resolved)
 462
 463        if any_correspondent is not None:
 464            resolved = await resolver.resolve_list("correspondents", any_correspondent)
 465            params["correspondent__id__in"] = ",".join(str(c) for c in resolved)
 466        elif not isinstance(correspondent, Unset):
 467            if correspondent is None:
 468                params["correspondent__isnull"] = "true"
 469            else:
 470                resolved_id = await resolver.resolve("correspondents", correspondent)
 471                params["correspondent__id"] = resolved_id
 472
 473        if exclude_correspondents is not None:
 474            resolved = await resolver.resolve_list("correspondents", exclude_correspondents)
 475            params["correspondent__id__none"] = ",".join(str(c) for c in resolved)
 476
 477        if document_type_name_contains is not None:
 478            params["document_type__name__icontains"] = document_type_name_contains
 479        if document_type_name_exact is not None:
 480            params["document_type__name__iexact"] = document_type_name_exact
 481
 482        if any_document_type is not None:
 483            resolved = await resolver.resolve_list("document_types", any_document_type)
 484            params["document_type__id__in"] = ",".join(str(d) for d in resolved)
 485        elif not isinstance(document_type, Unset):
 486            if document_type is None:
 487                params["document_type__isnull"] = "true"
 488            else:
 489                resolved_id = await resolver.resolve("document_types", document_type)
 490                params["document_type__id"] = resolved_id
 491
 492        if exclude_document_types is not None:
 493            resolved = await resolver.resolve_list("document_types", exclude_document_types)
 494            params["document_type__id__none"] = ",".join(str(d) for d in resolved)
 495
 496        if any_storage_paths is not None:
 497            resolved = await resolver.resolve_list("storage_paths", any_storage_paths)
 498            params["storage_path__id__in"] = ",".join(str(s) for s in resolved)
 499        elif not isinstance(storage_path, Unset):
 500            if storage_path is None:
 501                params["storage_path__isnull"] = "true"
 502            else:
 503                resolved_id = await resolver.resolve("storage_paths", storage_path)
 504                params["storage_path__id"] = resolved_id
 505
 506        if exclude_storage_paths is not None:
 507            resolved = await resolver.resolve_list("storage_paths", exclude_storage_paths)
 508            params["storage_path__id__none"] = ",".join(str(s) for s in resolved)
 509
 510        if not isinstance(owner, Unset):
 511            if owner is None:
 512                params["owner__isnull"] = "true"
 513            else:
 514                params["owner__id"] = owner
 515
 516        if exclude_owners is not None:
 517            params["owner__id__none"] = ",".join(str(o) for o in exclude_owners)
 518
 519        if custom_fields is not None:
 520            resolved = await resolver.resolve_list("custom_fields", custom_fields)
 521            params["custom_fields__id__all"] = ",".join(str(f) for f in resolved)
 522
 523        if any_custom_fields is not None:
 524            resolved = await resolver.resolve_list("custom_fields", any_custom_fields)
 525            params["custom_fields__id__in"] = ",".join(str(f) for f in resolved)
 526
 527        if exclude_custom_fields is not None:
 528            resolved = await resolver.resolve_list("custom_fields", exclude_custom_fields)
 529            params["custom_fields__id__none"] = ",".join(str(f) for f in resolved)
 530
 531        if custom_field_query is not None:
 532            params["custom_field_query"] = json.dumps(custom_field_query)
 533
 534        if not isinstance(archive_serial_number, Unset):
 535            if archive_serial_number is None:
 536                params["archive_serial_number__isnull"] = "true"
 537            else:
 538                params["archive_serial_number"] = archive_serial_number
 539
 540        if archive_serial_number_from is not None:
 541            params["archive_serial_number__gte"] = archive_serial_number_from
 542
 543        if archive_serial_number_till is not None:
 544            params["archive_serial_number__lte"] = archive_serial_number_till
 545
 546        if created_after is not None:
 547            params["created__date__gt"] = self._format_date_value(created_after)
 548
 549        if created_before is not None:
 550            params["created__date__lt"] = self._format_date_value(created_before)
 551
 552        if added_after is not None:
 553            key = "added__gt" if self._is_datetime(added_after) else "added__date__gt"
 554            params[key] = self._format_date_value(added_after)
 555
 556        if added_from is not None:
 557            key = "added__gte" if self._is_datetime(added_from) else "added__date__gte"
 558            params[key] = self._format_date_value(added_from)
 559
 560        if added_before is not None:
 561            key = "added__lt" if self._is_datetime(added_before) else "added__date__lt"
 562            params[key] = self._format_date_value(added_before)
 563
 564        if added_until is not None:
 565            key = "added__lte" if self._is_datetime(added_until) else "added__date__lte"
 566            params[key] = self._format_date_value(added_until)
 567
 568        if modified_after is not None:
 569            key = "modified__gt" if self._is_datetime(modified_after) else "modified__date__gt"
 570            params[key] = self._format_date_value(modified_after)
 571
 572        if modified_from is not None:
 573            key = "modified__gte" if self._is_datetime(modified_from) else "modified__date__gte"
 574            params[key] = self._format_date_value(modified_from)
 575
 576        if modified_before is not None:
 577            key = "modified__lt" if self._is_datetime(modified_before) else "modified__date__lt"
 578            params[key] = self._format_date_value(modified_before)
 579
 580        if modified_until is not None:
 581            key = "modified__lte" if self._is_datetime(modified_until) else "modified__date__lte"
 582            params[key] = self._format_date_value(modified_until)
 583
 584        if checksum is not None:
 585            params["checksum__iexact"] = checksum
 586
 587        if ordering is not None:
 588            params["ordering"] = f"-{ordering}" if descending else ordering
 589
 590        if page is not None:
 591            params["page"] = page
 592            raw = await self._core._session.get_page("/documents/", params=params)
 593            items = raw.items
 594            if max_results is not None:
 595                items = items[:max_results]
 596            return PagedResult(
 597                count=raw.count,
 598                next=raw.next,
 599                previous=raw.previous,
 600                all=raw.all_ids,
 601                results=[Document.model_validate(item) for item in items],
 602            )
 603
 604        raw = await self._core._session.get_all_pages_paged(
 605            "/documents/", params, max_results=max_results, on_page=on_page
 606        )
 607        return PagedResult(
 608            count=raw.count,
 609            next=raw.next,
 610            previous=raw.previous,
 611            all=raw.all_ids,
 612            results=[Document.model_validate(item) for item in raw.items],
 613        )
 614
 615    async def update(
 616        self,
 617        id: int,
 618        *,
 619        title: str | Unset = UNSET,
 620        content: str | Unset = UNSET,
 621        created: date | str | None | Unset = UNSET,
 622        correspondent: int | str | None | Unset = UNSET,
 623        document_type: int | str | None | Unset = UNSET,
 624        storage_path: int | str | None | Unset = UNSET,
 625        tags: List[int | str] | None | Unset = UNSET,
 626        archive_serial_number: int | None | Unset = UNSET,
 627        custom_fields: List[dict[str, Any]] | None | Unset = UNSET,
 628        owner: int | None | Unset = UNSET,
 629        set_permissions: SetPermissions | None | Unset = UNSET,
 630        remove_inbox_tags: bool | None | Unset = UNSET,
 631    ) -> Document:
 632        """Partially update a document (PATCH semantics).
 633
 634        Args:
 635            id: Numeric ID of the document to update.
 636            title: New document title.
 637            content: OCR text content of the document.
 638            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
 639                :class:`~datetime.date` object.
 640            correspondent: Correspondent to assign, as an ID or name.
 641                Pass ``None`` to clear the correspondent.
 642            document_type: Document type to assign, as an ID or name.
 643                Pass ``None`` to clear the document type.
 644            storage_path: Storage path to assign, as an ID or name.
 645                Pass ``None`` to clear the storage path.
 646            tags: Full replacement list of tags (IDs or names).
 647            archive_serial_number: Archive serial number to assign.
 648                Pass ``None`` to clear the archive serial number.
 649            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
 650            owner: Numeric user ID to assign as document owner.
 651                Pass ``None`` to clear the owner.
 652            set_permissions: Explicit view/change permission sets.
 653                Pass ``None`` to clear all permissions (overwrite with empty).
 654                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
 655            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
 656
 657        Returns:
 658            The updated :class:`~easypaperless.models.documents.Document`.
 659        """
 660        logger.info("Updating document id=%d", id)
 661        resolver = self._core._resolver
 662        payload: dict[str, Any] = {}
 663
 664        if not isinstance(title, Unset):
 665            payload["title"] = title
 666        if not isinstance(content, Unset):
 667            payload["content"] = content
 668        if not isinstance(created, Unset):
 669            payload["created"] = self._format_date_value(created) if created is not None else None
 670        if not isinstance(correspondent, Unset):
 671            payload["correspondent"] = (
 672                None
 673                if correspondent is None
 674                else await resolver.resolve("correspondents", correspondent)
 675            )
 676        if not isinstance(document_type, Unset):
 677            payload["document_type"] = (
 678                None
 679                if document_type is None
 680                else await resolver.resolve("document_types", document_type)
 681            )
 682        if not isinstance(storage_path, Unset):
 683            payload["storage_path"] = (
 684                None
 685                if storage_path is None
 686                else await resolver.resolve("storage_paths", storage_path)
 687            )
 688        if not isinstance(tags, Unset):
 689            payload["tags"] = await resolver.resolve_list("tags", tags or [])
 690        if not isinstance(archive_serial_number, Unset):
 691            payload["archive_serial_number"] = archive_serial_number
 692        if not isinstance(custom_fields, Unset):
 693            payload["custom_fields"] = custom_fields
 694        if not isinstance(owner, Unset):
 695            payload["owner"] = owner
 696        if not isinstance(set_permissions, Unset):
 697            payload["set_permissions"] = (
 698                SetPermissions().model_dump()
 699                if set_permissions is None
 700                else set_permissions.model_dump()
 701            )
 702        if not isinstance(remove_inbox_tags, Unset):
 703            payload["remove_inbox_tags"] = remove_inbox_tags
 704
 705        resp = await self._core._session.patch(f"/documents/{id}/", json=payload)
 706        return Document.model_validate(resp.json())
 707
 708    async def delete(self, id: int) -> None:
 709        """Permanently delete a document.
 710
 711        Args:
 712            id: Numeric ID of the document to delete.
 713
 714        Raises:
 715            ~easypaperless.exceptions.NotFoundError: If no document exists
 716                with that ID.
 717        """
 718        logger.info("Deleting document id=%d", id)
 719        await self._core._session.delete(f"/documents/{id}/")
 720
 721    async def download(self, id: int, *, original: bool = False) -> bytes:
 722        """Download the binary content of a document.
 723
 724        Args:
 725            id: Numeric ID of the document to download.
 726            original: If ``False`` *(default)*, returns the archived PDF
 727                (``GET /documents/{id}/download/``).
 728                If ``True``, returns the original uploaded file
 729                (``GET /documents/{id}/download/?original=true``).
 730
 731        Returns:
 732            Raw file bytes.
 733        """
 734        logger.info("Downloading document id=%d (original=%s)", id, original)
 735        path = f"/documents/{id}/download/"
 736        if original:
 737            path += "?original=true"
 738        resp = await self._core._session.get_download(path)
 739        content_type = resp.headers.get("content-type", "")
 740        if "text/html" in content_type or resp.content[:9].lower().startswith(b"<!doctype"):
 741            raise ServerError(
 742                f"Download returned an HTML page (content-type: {content_type!r}). "
 743                "The server redirected to a login page even after re-attaching auth.",
 744                status_code=None,
 745            )
 746        return resp.content
 747
 748    async def thumbnail(self, id: int) -> bytes:
 749        """Fetch the thumbnail image of a document.
 750
 751        Args:
 752            id: Numeric ID of the document whose thumbnail to retrieve.
 753
 754        Returns:
 755            Raw binary content of the thumbnail image.
 756
 757        Raises:
 758            ~easypaperless.exceptions.NotFoundError: If no document exists
 759                with that ID.
 760            ~easypaperless.exceptions.ServerError: If the server returns an
 761                HTML page (e.g. an auth redirect) instead of the image.
 762        """
 763        logger.info("Fetching thumbnail for document id=%d", id)
 764        resp = await self._core._session.get_download(f"/documents/{id}/thumb/")
 765        content_type = resp.headers.get("content-type", "")
 766        if "text/html" in content_type or resp.content[:9].lower().startswith(b"<!doctype"):
 767            raise ServerError(
 768                f"Thumbnail returned an HTML page (content-type: {content_type!r}). "
 769                "The server redirected to a login page even after re-attaching auth.",
 770                status_code=None,
 771            )
 772        return resp.content
 773
 774    async def upload(
 775        self,
 776        file: str | Path,
 777        *,
 778        title: str | Unset = UNSET,
 779        created: date | str | None = None,
 780        correspondent: int | str | None | Unset = UNSET,
 781        document_type: int | str | None | Unset = UNSET,
 782        storage_path: int | str | None | Unset = UNSET,
 783        tags: List[int | str] | None = None,
 784        archive_serial_number: int | None | Unset = UNSET,
 785        custom_fields: List[dict[str, Any]] | None = None,
 786        wait: bool = False,
 787        poll_interval: float | None = None,
 788        poll_timeout: float | None = None,
 789    ) -> str | Document:
 790        """Upload a document to paperless-ngx.
 791
 792        Args:
 793            file: Path to the file to upload.
 794            title: Title to assign to the document.
 795            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
 796                :class:`~datetime.date` object.
 797            correspondent: Correspondent to assign, as an ID or name.
 798            document_type: Document type to assign, as an ID or name.
 799            storage_path: Storage path to assign, as an ID or name.
 800            tags: Tags to assign, as IDs or names.
 801            archive_serial_number: Archive serial number to assign.
 802            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
 803            wait: If ``False`` *(default)*, returns immediately with the task ID.
 804                If ``True``, polls until processing completes.
 805            poll_interval: Seconds between task-status checks while waiting for
 806                processing to complete (requires ``wait=True``). Overrides the
 807                client-level default. When omitted, falls back to the client-level
 808                ``poll_interval`` (``2.0`` s unless changed at construction).
 809            poll_timeout: Maximum seconds to wait before raising
 810                :exc:`~easypaperless.exceptions.TaskTimeoutError` (requires
 811                ``wait=True``). Overrides the client-level default. When omitted,
 812                falls back to the client-level ``poll_timeout`` (``60.0`` s unless
 813                changed at construction).
 814
 815        Returns:
 816            The Celery task ID string when ``wait=False``, or the fully
 817            processed :class:`~easypaperless.models.documents.Document`
 818            when ``wait=True``.
 819
 820        Raises:
 821            ~easypaperless.exceptions.UploadError: If processing fails.
 822            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
 823        """
 824        resolver = self._core._resolver
 825        file_path = Path(file)
 826        file_bytes = file_path.read_bytes()
 827        logger.info("Uploading %r (%d bytes)", file_path.name, len(file_bytes))
 828
 829        data: dict[str, Any] = {}
 830        if not isinstance(title, Unset):
 831            data["title"] = title
 832        if created is not None:
 833            data["created"] = self._format_date_value(created)
 834        if not isinstance(correspondent, Unset) and correspondent is not None:
 835            data["correspondent"] = await resolver.resolve("correspondents", correspondent)
 836        if not isinstance(document_type, Unset) and document_type is not None:
 837            data["document_type"] = await resolver.resolve("document_types", document_type)
 838        if not isinstance(storage_path, Unset) and storage_path is not None:
 839            data["storage_path"] = await resolver.resolve("storage_paths", storage_path)
 840        if tags is not None:
 841            resolved = await resolver.resolve_list("tags", tags)
 842            data["tags"] = resolved
 843        if not isinstance(archive_serial_number, Unset) and archive_serial_number is not None:
 844            data["archive_serial_number"] = archive_serial_number
 845        if custom_fields is not None:
 846            data["custom_fields"] = json.dumps(custom_fields)
 847
 848        files = {"document": (file_path.name, file_bytes)}
 849        resp = await self._core._session.post("/documents/post_document/", data=data, files=files)
 850        task_id: str = resp.text.strip('"')
 851        logger.debug("Upload accepted, task_id=%r", task_id)
 852
 853        if not wait:
 854            return task_id
 855
 856        interval = poll_interval if poll_interval is not None else self._core._poll_interval
 857        timeout = poll_timeout if poll_timeout is not None else self._core._poll_timeout
 858        return await self._poll_task(task_id, poll_interval=interval, poll_timeout=timeout)
 859
 860    async def _poll_task(
 861        self, task_id: str, *, poll_interval: float, poll_timeout: float
 862    ) -> Document:
 863        start = time.monotonic()
 864        deadline = start + poll_timeout
 865        while time.monotonic() < deadline:
 866            resp = await self._core._session.get("/tasks/", params={"task_id": task_id})
 867            tasks = resp.json()
 868            if not tasks:
 869                await asyncio.sleep(poll_interval)
 870                continue
 871
 872            task = Task.model_validate(tasks[0])
 873            elapsed = time.monotonic() - start
 874            logger.debug(
 875                "Polling task %r (status=%s, elapsed=%.1fs)",
 876                task_id,
 877                task.status.value if task.status is not None else "unknown",
 878                elapsed,
 879            )
 880            if task.status == TaskStatus.SUCCESS:
 881                if task.related_document is None:
 882                    raise UploadError(f"Task {task_id!r} succeeded but returned no document ID")
 883                doc_id = int(task.related_document)
 884                logger.info("Task %r succeeded, document_id=%d", task_id, doc_id)
 885                return await self.get(doc_id)
 886            elif task.status == TaskStatus.FAILURE:
 887                logger.warning("Task %r failed: %s", task_id, task.result)
 888                raise UploadError(f"Document processing failed: {task.result}")
 889            elif task.status == TaskStatus.REVOKED:
 890                logger.warning("Task %r was revoked", task_id)
 891                raise UploadError(f"Task {task_id!r} was revoked")
 892            await asyncio.sleep(poll_interval)
 893
 894        elapsed = time.monotonic() - start
 895        logger.warning("Task %r timed out after %.1fs", task_id, elapsed)
 896        raise TaskTimeoutError(f"Task {task_id!r} did not complete within {poll_timeout}s")
 897
 898    # -------------------------------------------------------------------------
 899    # Document bulk operations
 900    # -------------------------------------------------------------------------
 901
 902    async def _bulk_edit(self, document_ids: List[int], method: str, **parameters: Any) -> None:
 903        """Execute a bulk-edit operation on a list of documents.
 904
 905        Args:
 906            document_ids: List of document IDs to operate on.
 907            method: Bulk-edit method name (e.g. ``"add_tag"``, ``"delete"``).
 908            **parameters: Additional keyword arguments forwarded to the API.
 909        """
 910        payload = {"documents": document_ids, "method": method, "parameters": parameters}
 911        await self._core._session.post("/documents/bulk_edit/", json=payload, timeout=120.0)
 912
 913    async def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
 914        """Add a tag to multiple documents in a single request.
 915
 916        Args:
 917            document_ids: List of document IDs to tag.
 918            tag: Tag to add, as an ID or name.
 919        """
 920        logger.info("Bulk adding tag %r to %d documents", tag, len(document_ids))
 921        tag_id = await self._core._resolver.resolve("tags", tag)
 922        await self._bulk_edit(document_ids, "add_tag", tag=tag_id)
 923
 924    async def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
 925        """Remove a tag from multiple documents in a single request.
 926
 927        Args:
 928            document_ids: List of document IDs to un-tag.
 929            tag: Tag to remove, as an ID or name.
 930        """
 931        logger.info("Bulk removing tag %r from %d documents", tag, len(document_ids))
 932        tag_id = await self._core._resolver.resolve("tags", tag)
 933        await self._bulk_edit(document_ids, "remove_tag", tag=tag_id)
 934
 935    async def bulk_modify_tags(
 936        self,
 937        document_ids: List[int],
 938        *,
 939        add_tags: List[int | str] | None = None,
 940        remove_tags: List[int | str] | None = None,
 941    ) -> None:
 942        """Add and/or remove tags on multiple documents atomically.
 943
 944        Args:
 945            document_ids: List of document IDs to modify.
 946            add_tags: Tags to add, as IDs or names.
 947            remove_tags: Tags to remove, as IDs or names.
 948        """
 949        logger.info("Bulk modifying tags on %d documents", len(document_ids))
 950        resolver = self._core._resolver
 951        add_ids = await resolver.resolve_list("tags", add_tags or [])
 952        remove_ids = await resolver.resolve_list("tags", remove_tags or [])
 953        await self._bulk_edit(document_ids, "modify_tags", add_tags=add_ids, remove_tags=remove_ids)
 954
 955    async def bulk_delete(self, document_ids: List[int]) -> None:
 956        """Permanently delete multiple documents in a single request.
 957
 958        Args:
 959            document_ids: List of document IDs to delete.
 960        """
 961        logger.info("Bulk deleting %d documents", len(document_ids))
 962        await self._bulk_edit(document_ids, "delete")
 963
 964    async def bulk_set_correspondent(
 965        self, document_ids: List[int], correspondent: int | str | None
 966    ) -> None:
 967        """Assign a correspondent to multiple documents in a single request.
 968
 969        Args:
 970            document_ids: List of document IDs to modify.
 971            correspondent: Correspondent to assign, as an ID or name.
 972                Pass ``None`` to clear.
 973        """
 974        logger.info(
 975            "Bulk setting correspondent %r on %d documents", correspondent, len(document_ids)
 976        )
 977        cor_id: int | None = None
 978        if correspondent is not None:
 979            cor_id = await self._core._resolver.resolve("correspondents", correspondent)
 980        await self._bulk_edit(document_ids, "set_correspondent", correspondent=cor_id)
 981
 982    async def bulk_set_document_type(
 983        self, document_ids: List[int], document_type: int | str | None
 984    ) -> None:
 985        """Assign a document type to multiple documents in a single request.
 986
 987        Args:
 988            document_ids: List of document IDs to modify.
 989            document_type: Document type to assign, as an ID or name.
 990                Pass ``None`` to clear.
 991        """
 992        logger.info(
 993            "Bulk setting document type %r on %d documents", document_type, len(document_ids)
 994        )
 995        dt_id: int | None = None
 996        if document_type is not None:
 997            dt_id = await self._core._resolver.resolve("document_types", document_type)
 998        await self._bulk_edit(document_ids, "set_document_type", document_type=dt_id)
 999
1000    async def bulk_set_storage_path(
1001        self, document_ids: List[int], storage_path: int | str | None
1002    ) -> None:
1003        """Assign a storage path to multiple documents in a single request.
1004
1005        Args:
1006            document_ids: List of document IDs to modify.
1007            storage_path: Storage path to assign, as an ID or name.
1008                Pass ``None`` to clear.
1009        """
1010        logger.info("Bulk setting storage path %r on %d documents", storage_path, len(document_ids))
1011        sp_id: int | None = None
1012        if storage_path is not None:
1013            sp_id = await self._core._resolver.resolve("storage_paths", storage_path)
1014        await self._bulk_edit(document_ids, "set_storage_path", storage_path=sp_id)
1015
1016    async def bulk_modify_custom_fields(
1017        self,
1018        document_ids: List[int],
1019        *,
1020        add_fields: List[dict[str, Any]] | None = None,
1021        remove_fields: List[int] | None = None,
1022    ) -> None:
1023        """Add and/or remove custom field values on multiple documents.
1024
1025        Args:
1026            document_ids: List of document IDs to modify.
1027            add_fields: Custom-field value dicts to add.
1028            remove_fields: Custom-field IDs whose values should be removed.
1029        """
1030        logger.info("Bulk modifying custom fields on %d documents", len(document_ids))
1031        await self._bulk_edit(
1032            document_ids,
1033            "modify_custom_fields",
1034            add_custom_fields=add_fields or [],
1035            remove_custom_fields=remove_fields or [],
1036        )
1037
1038    async def bulk_set_permissions(
1039        self,
1040        document_ids: List[int],
1041        *,
1042        set_permissions: SetPermissions | Unset = UNSET,
1043        owner: int | None | Unset = UNSET,
1044        merge: bool = False,
1045    ) -> None:
1046        """Set permissions and/or owner on multiple documents.
1047
1048        Args:
1049            document_ids: List of document IDs to modify.
1050            set_permissions: Explicit view/change permission sets.
1051                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
1052            owner: Numeric user ID to assign as document owner.
1053                Pass ``None`` to clear the owner.
1054                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
1055            merge: When ``True``, new permissions are merged with existing ones.
1056        """
1057        logger.info("Bulk setting permissions on %d documents", len(document_ids))
1058        params: dict[str, Any] = {"merge": merge}
1059        if not isinstance(set_permissions, Unset):
1060            params["set_permissions"] = set_permissions.model_dump()
1061        if not isinstance(owner, Unset):
1062            params["owner"] = owner
1063        await self._bulk_edit(document_ids, "set_permissions", **params)
1064
1065    async def bulk_download(
1066        self,
1067        document_ids: List[int],
1068        *,
1069        content: Literal["archive", "originals", "both"] = "archive",
1070        compression: Literal["none", "deflated", "bzip2", "lzma"] = "none",
1071        follow_formatting: bool = False,
1072    ) -> bytes:
1073        """Download multiple documents as a single ZIP archive.
1074
1075        Args:
1076            document_ids: List of document IDs to include in the ZIP.
1077            content: File variant to include.  One of ``"archive"`` *(default)*,
1078                ``"originals"``, or ``"both"``.
1079            compression: ZIP compression algorithm.  One of ``"none"`` *(default)*,
1080                ``"deflated"``, ``"bzip2"``, or ``"lzma"``.
1081            follow_formatting: When ``True``, filenames inside the ZIP follow
1082                the storage path formatting configured in paperless-ngx.
1083                Default: ``False``.
1084
1085        Returns:
1086            Raw bytes of the ZIP archive.
1087        """
1088        logger.info(
1089            "Bulk downloading %d documents (content=%s, compression=%s)",
1090            len(document_ids),
1091            content,
1092            compression,
1093        )
1094        payload: dict[str, Any] = {
1095            "documents": document_ids,
1096            "content": content,
1097            "compression": compression,
1098            "follow_formatting": follow_formatting,
1099        }
1100        resp = await self._core._session.post("/documents/bulk_download/", json=payload)
1101        return resp.content

Accessor for documents: client.documents.

DocumentsResource(core: easypaperless.client._ClientCore)
179    def __init__(self, core: _ClientCore) -> None:
180        self._core = core
181        self.notes = NotesResource(core)
notes
async def history( self, document_id: int, *, page: int | None = None, page_size: int | None = None) -> easypaperless.PagedResult[AuditLogEntry]:
183    async def history(
184        self,
185        document_id: int,
186        *,
187        page: int | None = None,
188        page_size: int | None = None,
189    ) -> PagedResult[AuditLogEntry]:
190        """Fetch the audit log for a document.
191
192        The paperless-ngx ``/api/documents/{id}/history/`` endpoint returns a
193        plain JSON array rather than a paginated envelope.  This method wraps
194        the response into a :class:`~easypaperless.models.paged_result.PagedResult`
195        so callers always receive a consistent return type.
196
197        Args:
198            document_id: Numeric ID of the document whose history to retrieve.
199            page: Forwarded to the API as a query parameter when provided.
200                Effect depends on the paperless-ngx version; the server may
201                ignore this parameter.
202            page_size: Forwarded to the API as a query parameter when provided.
203
204        Returns:
205            :class:`~easypaperless.models.paged_result.PagedResult` of
206            :class:`~easypaperless.models.documents.AuditLogEntry` objects,
207            ordered by timestamp descending.
208
209        Raises:
210            ~easypaperless.exceptions.NotFoundError: If no document exists
211                with that ID.
212        """
213        logger.info("Fetching history for document id=%d", document_id)
214        path = f"/documents/{document_id}/history/"
215        params: dict[str, Any] = {}
216        if page is not None:
217            params["page"] = page
218        if page_size is not None:
219            params["page_size"] = page_size
220
221        resp = await self._core._session.get(path, params=params or None)
222        data = resp.json()
223
224        if isinstance(data, list):
225            entries = [AuditLogEntry.model_validate(item) for item in data]
226            entry_ids: list[int] = [e.id for e in entries]
227            return PagedResult(
228                count=len(entries),
229                next=None,
230                previous=None,
231                all=entry_ids if entry_ids else None,
232                results=entries,
233            )
234
235        # Forward-compatible: handle a paginated envelope if the API ever adds one.
236        items: list[Any] = list(data.get("results", []))
237        count: int = data.get("count", 0)
238        all_ids: list[int] | None = data.get("all")
239        return PagedResult(
240            count=count,
241            next=data.get("next"),
242            previous=data.get("previous"),
243            all=all_ids,
244            results=[AuditLogEntry.model_validate(item) for item in items],
245        )

Fetch the audit log for a document.

The paperless-ngx /api/documents/{id}/history/ endpoint returns a plain JSON array rather than a paginated envelope. This method wraps the response into a ~easypaperless.models.paged_result.PagedResult so callers always receive a consistent return type.

Arguments:
  • document_id: Numeric ID of the document whose history to retrieve.
  • page: Forwarded to the API as a query parameter when provided. Effect depends on the paperless-ngx version; the server may ignore this parameter.
  • page_size: Forwarded to the API as a query parameter when provided.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.AuditLogEntry objects, ordered by timestamp descending.

Raises:
async def get( self, id: int, *, include_metadata: bool = False) -> easypaperless.Document:
263    async def get(self, id: int, *, include_metadata: bool = False) -> Document:
264        """Fetch a single document by its ID.
265
266        Args:
267            id: Numeric paperless-ngx document ID.
268            include_metadata: When ``True``, the extended file-level metadata
269                is fetched concurrently and attached to the document.
270                Default: ``False``.
271
272        Returns:
273            The :class:`~easypaperless.models.documents.Document` with the
274            given ID.
275
276        Raises:
277            ~easypaperless.exceptions.NotFoundError: If no document exists
278                with that ID.
279        """
280        logger.info("Getting document id=%d", id)
281        if include_metadata:
282            doc_resp, meta_resp = await asyncio.gather(
283                self._core._session.get(f"/documents/{id}/"),
284                self._core._session.get(f"/documents/{id}/metadata/"),
285            )
286            data = doc_resp.json()
287            data["metadata"] = meta_resp.json()
288        else:
289            resp = await self._core._session.get(f"/documents/{id}/")
290            data = resp.json()
291        return Document.model_validate(data)

Fetch a single document by its ID.

Arguments:
  • id: Numeric paperless-ngx document ID.
  • include_metadata: When True, the extended file-level metadata is fetched concurrently and attached to the document. Default: False.
Returns:

The ~easypaperless.models.documents.Document with the given ID.

Raises:
async def get_metadata(self, id: int) -> easypaperless.DocumentMetadata:
293    async def get_metadata(self, id: int) -> DocumentMetadata:
294        """Fetch the extended file-level metadata for a document.
295
296        Args:
297            id: Numeric paperless-ngx document ID.
298
299        Returns:
300            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
301
302        Raises:
303            ~easypaperless.exceptions.NotFoundError: If no document exists
304                with that ID.
305        """
306        logger.info("Getting metadata for document id=%d", id)
307        resp = await self._core._session.get(f"/documents/{id}/metadata/")
308        return DocumentMetadata.model_validate(resp.json())

Fetch the extended file-level metadata for a document.

Arguments:
  • id: Numeric paperless-ngx document ID.
Returns:

A ~easypaperless.models.documents.DocumentMetadata instance.

Raises:
async def list( self, *, search: str | None = None, search_mode: str = 'title_or_content', ids: Optional[List[int]] = None, tags: Optional[List[Union[str, int]]] = None, any_tags: Optional[List[Union[str, int]]] = None, exclude_tags: Optional[List[Union[str, int]]] = None, correspondent: int | str | None | easypaperless.Unset = UNSET, any_correspondent: Optional[List[Union[str, int]]] = None, exclude_correspondents: Optional[List[Union[str, int]]] = None, document_type: int | str | None | easypaperless.Unset = UNSET, document_type_name_contains: str | None = None, document_type_name_exact: str | None = None, any_document_type: Optional[List[Union[str, int]]] = None, exclude_document_types: Optional[List[Union[str, int]]] = None, storage_path: int | str | None | easypaperless.Unset = UNSET, any_storage_paths: Optional[List[Union[str, int]]] = None, exclude_storage_paths: Optional[List[Union[str, int]]] = None, owner: int | None | easypaperless.Unset = UNSET, exclude_owners: Optional[List[int]] = None, custom_fields: Optional[List[Union[str, int]]] = None, any_custom_fields: Optional[List[Union[str, int]]] = None, exclude_custom_fields: Optional[List[Union[str, int]]] = None, custom_field_query: Optional[List[Any]] = None, archive_serial_number: int | None | easypaperless.Unset = UNSET, archive_serial_number_from: int | None = None, archive_serial_number_till: int | None = None, created_after: datetime.date | str | None = None, created_before: datetime.date | str | None = None, added_after: datetime.date | datetime.datetime | str | None = None, added_from: datetime.date | datetime.datetime | str | None = None, added_before: datetime.date | datetime.datetime | str | None = None, added_until: datetime.date | datetime.datetime | str | None = None, modified_after: datetime.date | datetime.datetime | str | None = None, modified_from: datetime.date | datetime.datetime | str | None = None, modified_before: datetime.date | datetime.datetime | str | None = None, modified_until: datetime.date | datetime.datetime | str | None = None, checksum: str | None = None, page_size: int = 25, page: int | None = None, ordering: str | None = None, descending: bool = False, max_results: int | None = None, on_page: Callable[[int, int | None], None] | None = None) -> easypaperless.PagedResult[Document]:
310    async def list(
311        self,
312        *,
313        search: str | None = None,
314        search_mode: str = "title_or_content",
315        ids: List[int] | None = None,
316        tags: List[int | str] | None = None,
317        any_tags: List[int | str] | None = None,
318        exclude_tags: List[int | str] | None = None,
319        correspondent: int | str | None | Unset = UNSET,
320        any_correspondent: List[int | str] | None = None,
321        exclude_correspondents: List[int | str] | None = None,
322        document_type: int | str | None | Unset = UNSET,
323        document_type_name_contains: str | None = None,
324        document_type_name_exact: str | None = None,
325        any_document_type: List[int | str] | None = None,
326        exclude_document_types: List[int | str] | None = None,
327        storage_path: int | str | None | Unset = UNSET,
328        any_storage_paths: List[int | str] | None = None,
329        exclude_storage_paths: List[int | str] | None = None,
330        owner: int | None | Unset = UNSET,
331        exclude_owners: List[int] | None = None,
332        custom_fields: List[int | str] | None = None,
333        any_custom_fields: List[int | str] | None = None,
334        exclude_custom_fields: List[int | str] | None = None,
335        custom_field_query: List[Any] | None = None,
336        archive_serial_number: int | None | Unset = UNSET,
337        archive_serial_number_from: int | None = None,
338        archive_serial_number_till: int | None = None,
339        created_after: date | str | None = None,
340        created_before: date | str | None = None,
341        added_after: date | datetime | str | None = None,
342        added_from: date | datetime | str | None = None,
343        added_before: date | datetime | str | None = None,
344        added_until: date | datetime | str | None = None,
345        modified_after: date | datetime | str | None = None,
346        modified_from: date | datetime | str | None = None,
347        modified_before: date | datetime | str | None = None,
348        modified_until: date | datetime | str | None = None,
349        checksum: str | None = None,
350        page_size: int = 25,
351        page: int | None = None,
352        ordering: str | None = None,
353        descending: bool = False,
354        max_results: int | None = None,
355        on_page: Callable[[int, int | None], None] | None = None,
356    ) -> PagedResult[Document]:
357        """Return a filtered list of documents.
358
359        All tag, correspondent, document-type, storage-path, and custom-field
360        parameters accept either integer IDs or string names.
361
362        When ``page`` is ``None`` (the default), all pages are fetched
363        automatically and ``next`` / ``previous`` in the returned
364        :class:`~easypaperless.models.paged_result.PagedResult` are always
365        ``None`` — even if ``max_results`` truncates the final result set.
366        ``count`` always reflects the server total, not the truncated length.
367        When ``page`` is set to a specific integer, only that one page is
368        fetched and ``next`` / ``previous`` contain the raw API values.
369
370        Args:
371            search: Search string.  Behaviour depends on ``search_mode``.
372            search_mode: How ``search`` is applied.  One of:
373                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
374                ``"original_filename"``.
375            ids: Return only documents whose ID is in this list.
376            tags: Documents must have **all** of these tags (AND semantics).
377            any_tags: Documents must have **at least one** of these tags.
378            exclude_tags: Documents must have **none** of these tags.
379            correspondent: Filter to documents assigned to this correspondent.
380                Pass ``None`` to return only documents with no correspondent set.
381            any_correspondent: Filter to documents assigned to any of these.
382            exclude_correspondents: Exclude documents assigned to any of these.
383            document_type: Filter to documents of exactly this type.
384                Pass ``None`` to return only documents with no document type set.
385            document_type_name_contains: Case-insensitive substring filter on document type name.
386            document_type_name_exact: Case-insensitive exact match on document type name.
387            any_document_type: Filter to documents whose type is any of these.
388            exclude_document_types: Exclude documents whose type is any of these.
389            storage_path: Filter to documents assigned to this storage path.
390                Pass ``None`` to return only documents with no storage path set.
391            any_storage_paths: Filter to documents assigned to any of these paths.
392            exclude_storage_paths: Exclude documents assigned to any of these paths.
393            owner: Filter to documents owned by this user ID.
394                Pass ``None`` to return only documents with no owner set.
395            exclude_owners: Exclude documents owned by any of these user IDs.
396            custom_fields: Documents must have **all** of these custom fields set.
397            any_custom_fields: Documents must have **at least one** of these fields.
398            exclude_custom_fields: Documents must have **none** of these fields.
399            custom_field_query: Filter documents by custom field values using a nested
400                query structure. See the `paperless-ngx API docs
401                <https://docs.paperless-ngx.com/api/#filtering-by-custom-fields>`_ for
402                the query format.
403            archive_serial_number: Filter by exact archive serial number.
404                Pass ``None`` to return only documents with no ASN set.
405            archive_serial_number_from: Filter by ASN >= this value.
406            archive_serial_number_till: Filter by ASN <= this value.
407            created_after: Only documents created after this date.
408                String input must be ISO-8601: ``"YYYY-MM-DD"``.
409            created_before: Only documents created before this date.
410                String input must be ISO-8601: ``"YYYY-MM-DD"``.
411            added_after: Only documents added after this date/time.
412                String input must be ISO-8601: ``"YYYY-MM-DD"`` for date precision or
413                ``"YYYY-MM-DDTHH:MM:SS"`` for datetime precision.
414            added_from: Only documents added on or after this date/time.
415                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
416            added_before: Only documents added before this date/time.
417                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
418            added_until: Only documents added on or before this date/time.
419                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
420            modified_after: Only documents modified after this date/time.
421                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
422            modified_from: Only documents modified on or after this date/time.
423                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
424            modified_before: Only documents modified before this date/time.
425                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
426            modified_until: Only documents modified on or before this date/time.
427                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
428            checksum: MD5 checksum of the original file (exact match).
429            page_size: Number of results per API page.  Default: ``25``.
430            page: Return only this specific page (1-based).
431            ordering: Field name to sort by.
432            descending: When ``True``, reverses the sort direction.
433            max_results: Stop after collecting this many documents.
434            on_page: Callback invoked after each page fetch.
435
436        Returns:
437            :class:`~easypaperless.models.paged_result.PagedResult` of
438            :class:`~easypaperless.models.documents.Document` objects.
439        """
440        logger.info("Listing documents")
441        resolver = self._core._resolver
442        params: dict[str, Any] = {"page_size": page_size}
443
444        if search is not None:
445            api_param = _SEARCH_MODE_MAP.get(search_mode, "search")
446            params[api_param] = search
447
448        if ids is not None:
449            params["id__in"] = ",".join(str(i) for i in ids)
450
451        if tags is not None:
452            resolved = await resolver.resolve_list("tags", tags)
453            params["tags__id__all"] = ",".join(str(t) for t in resolved)
454
455        if any_tags is not None:
456            resolved = await resolver.resolve_list("tags", any_tags)
457            params["tags__id__in"] = ",".join(str(t) for t in resolved)
458
459        if exclude_tags is not None:
460            resolved = await resolver.resolve_list("tags", exclude_tags)
461            params["tags__id__none"] = ",".join(str(t) for t in resolved)
462
463        if any_correspondent is not None:
464            resolved = await resolver.resolve_list("correspondents", any_correspondent)
465            params["correspondent__id__in"] = ",".join(str(c) for c in resolved)
466        elif not isinstance(correspondent, Unset):
467            if correspondent is None:
468                params["correspondent__isnull"] = "true"
469            else:
470                resolved_id = await resolver.resolve("correspondents", correspondent)
471                params["correspondent__id"] = resolved_id
472
473        if exclude_correspondents is not None:
474            resolved = await resolver.resolve_list("correspondents", exclude_correspondents)
475            params["correspondent__id__none"] = ",".join(str(c) for c in resolved)
476
477        if document_type_name_contains is not None:
478            params["document_type__name__icontains"] = document_type_name_contains
479        if document_type_name_exact is not None:
480            params["document_type__name__iexact"] = document_type_name_exact
481
482        if any_document_type is not None:
483            resolved = await resolver.resolve_list("document_types", any_document_type)
484            params["document_type__id__in"] = ",".join(str(d) for d in resolved)
485        elif not isinstance(document_type, Unset):
486            if document_type is None:
487                params["document_type__isnull"] = "true"
488            else:
489                resolved_id = await resolver.resolve("document_types", document_type)
490                params["document_type__id"] = resolved_id
491
492        if exclude_document_types is not None:
493            resolved = await resolver.resolve_list("document_types", exclude_document_types)
494            params["document_type__id__none"] = ",".join(str(d) for d in resolved)
495
496        if any_storage_paths is not None:
497            resolved = await resolver.resolve_list("storage_paths", any_storage_paths)
498            params["storage_path__id__in"] = ",".join(str(s) for s in resolved)
499        elif not isinstance(storage_path, Unset):
500            if storage_path is None:
501                params["storage_path__isnull"] = "true"
502            else:
503                resolved_id = await resolver.resolve("storage_paths", storage_path)
504                params["storage_path__id"] = resolved_id
505
506        if exclude_storage_paths is not None:
507            resolved = await resolver.resolve_list("storage_paths", exclude_storage_paths)
508            params["storage_path__id__none"] = ",".join(str(s) for s in resolved)
509
510        if not isinstance(owner, Unset):
511            if owner is None:
512                params["owner__isnull"] = "true"
513            else:
514                params["owner__id"] = owner
515
516        if exclude_owners is not None:
517            params["owner__id__none"] = ",".join(str(o) for o in exclude_owners)
518
519        if custom_fields is not None:
520            resolved = await resolver.resolve_list("custom_fields", custom_fields)
521            params["custom_fields__id__all"] = ",".join(str(f) for f in resolved)
522
523        if any_custom_fields is not None:
524            resolved = await resolver.resolve_list("custom_fields", any_custom_fields)
525            params["custom_fields__id__in"] = ",".join(str(f) for f in resolved)
526
527        if exclude_custom_fields is not None:
528            resolved = await resolver.resolve_list("custom_fields", exclude_custom_fields)
529            params["custom_fields__id__none"] = ",".join(str(f) for f in resolved)
530
531        if custom_field_query is not None:
532            params["custom_field_query"] = json.dumps(custom_field_query)
533
534        if not isinstance(archive_serial_number, Unset):
535            if archive_serial_number is None:
536                params["archive_serial_number__isnull"] = "true"
537            else:
538                params["archive_serial_number"] = archive_serial_number
539
540        if archive_serial_number_from is not None:
541            params["archive_serial_number__gte"] = archive_serial_number_from
542
543        if archive_serial_number_till is not None:
544            params["archive_serial_number__lte"] = archive_serial_number_till
545
546        if created_after is not None:
547            params["created__date__gt"] = self._format_date_value(created_after)
548
549        if created_before is not None:
550            params["created__date__lt"] = self._format_date_value(created_before)
551
552        if added_after is not None:
553            key = "added__gt" if self._is_datetime(added_after) else "added__date__gt"
554            params[key] = self._format_date_value(added_after)
555
556        if added_from is not None:
557            key = "added__gte" if self._is_datetime(added_from) else "added__date__gte"
558            params[key] = self._format_date_value(added_from)
559
560        if added_before is not None:
561            key = "added__lt" if self._is_datetime(added_before) else "added__date__lt"
562            params[key] = self._format_date_value(added_before)
563
564        if added_until is not None:
565            key = "added__lte" if self._is_datetime(added_until) else "added__date__lte"
566            params[key] = self._format_date_value(added_until)
567
568        if modified_after is not None:
569            key = "modified__gt" if self._is_datetime(modified_after) else "modified__date__gt"
570            params[key] = self._format_date_value(modified_after)
571
572        if modified_from is not None:
573            key = "modified__gte" if self._is_datetime(modified_from) else "modified__date__gte"
574            params[key] = self._format_date_value(modified_from)
575
576        if modified_before is not None:
577            key = "modified__lt" if self._is_datetime(modified_before) else "modified__date__lt"
578            params[key] = self._format_date_value(modified_before)
579
580        if modified_until is not None:
581            key = "modified__lte" if self._is_datetime(modified_until) else "modified__date__lte"
582            params[key] = self._format_date_value(modified_until)
583
584        if checksum is not None:
585            params["checksum__iexact"] = checksum
586
587        if ordering is not None:
588            params["ordering"] = f"-{ordering}" if descending else ordering
589
590        if page is not None:
591            params["page"] = page
592            raw = await self._core._session.get_page("/documents/", params=params)
593            items = raw.items
594            if max_results is not None:
595                items = items[:max_results]
596            return PagedResult(
597                count=raw.count,
598                next=raw.next,
599                previous=raw.previous,
600                all=raw.all_ids,
601                results=[Document.model_validate(item) for item in items],
602            )
603
604        raw = await self._core._session.get_all_pages_paged(
605            "/documents/", params, max_results=max_results, on_page=on_page
606        )
607        return PagedResult(
608            count=raw.count,
609            next=raw.next,
610            previous=raw.previous,
611            all=raw.all_ids,
612            results=[Document.model_validate(item) for item in raw.items],
613        )

Return a filtered list of documents.

All tag, correspondent, document-type, storage-path, and custom-field parameters accept either integer IDs or string names.

When page is None (the default), all pages are fetched automatically and next / previous in the returned ~easypaperless.models.paged_result.PagedResult are always None — even if max_results truncates the final result set. count always reflects the server total, not the truncated length. When page is set to a specific integer, only that one page is fetched and next / previous contain the raw API values.

Arguments:
  • search: Search string. Behaviour depends on search_mode.
  • search_mode: How search is applied. One of: "title_or_content" (default), "title", "query", "original_filename".
  • ids: Return only documents whose ID is in this list.
  • tags: Documents must have all of these tags (AND semantics).
  • any_tags: Documents must have at least one of these tags.
  • exclude_tags: Documents must have none of these tags.
  • correspondent: Filter to documents assigned to this correspondent. Pass None to return only documents with no correspondent set.
  • any_correspondent: Filter to documents assigned to any of these.
  • exclude_correspondents: Exclude documents assigned to any of these.
  • document_type: Filter to documents of exactly this type. Pass None to return only documents with no document type set.
  • document_type_name_contains: Case-insensitive substring filter on document type name.
  • document_type_name_exact: Case-insensitive exact match on document type name.
  • any_document_type: Filter to documents whose type is any of these.
  • exclude_document_types: Exclude documents whose type is any of these.
  • storage_path: Filter to documents assigned to this storage path. Pass None to return only documents with no storage path set.
  • any_storage_paths: Filter to documents assigned to any of these paths.
  • exclude_storage_paths: Exclude documents assigned to any of these paths.
  • owner: Filter to documents owned by this user ID. Pass None to return only documents with no owner set.
  • exclude_owners: Exclude documents owned by any of these user IDs.
  • custom_fields: Documents must have all of these custom fields set.
  • any_custom_fields: Documents must have at least one of these fields.
  • exclude_custom_fields: Documents must have none of these fields.
  • custom_field_query: Filter documents by custom field values using a nested query structure. See the paperless-ngx API docs for the query format.
  • archive_serial_number: Filter by exact archive serial number. Pass None to return only documents with no ASN set.
  • archive_serial_number_from: Filter by ASN >= this value.
  • archive_serial_number_till: Filter by ASN <= this value.
  • created_after: Only documents created after this date. String input must be ISO-8601: "YYYY-MM-DD".
  • created_before: Only documents created before this date. String input must be ISO-8601: "YYYY-MM-DD".
  • added_after: Only documents added after this date/time. String input must be ISO-8601: "YYYY-MM-DD" for date precision or "YYYY-MM-DDTHH:MM:SS" for datetime precision.
  • added_from: Only documents added on or after this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • added_before: Only documents added before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • added_until: Only documents added on or before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_after: Only documents modified after this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_from: Only documents modified on or after this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_before: Only documents modified before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_until: Only documents modified on or before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • checksum: MD5 checksum of the original file (exact match).
  • page_size: Number of results per API page. Default: 25.
  • page: Return only this specific page (1-based).
  • ordering: Field name to sort by.
  • descending: When True, reverses the sort direction.
  • max_results: Stop after collecting this many documents.
  • on_page: Callback invoked after each page fetch.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.Document objects.

async def update( self, id: int, *, title: str | easypaperless.Unset = UNSET, content: str | easypaperless.Unset = UNSET, created: datetime.date | str | None | easypaperless.Unset = UNSET, correspondent: int | str | None | easypaperless.Unset = UNSET, document_type: int | str | None | easypaperless.Unset = UNSET, storage_path: int | str | None | easypaperless.Unset = UNSET, tags: Union[List[Union[str, int]], NoneType, easypaperless.Unset] = UNSET, archive_serial_number: int | None | easypaperless.Unset = UNSET, custom_fields: Union[List[dict[str, Any]], NoneType, easypaperless.Unset] = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET, remove_inbox_tags: bool | None | easypaperless.Unset = UNSET) -> easypaperless.Document:
615    async def update(
616        self,
617        id: int,
618        *,
619        title: str | Unset = UNSET,
620        content: str | Unset = UNSET,
621        created: date | str | None | Unset = UNSET,
622        correspondent: int | str | None | Unset = UNSET,
623        document_type: int | str | None | Unset = UNSET,
624        storage_path: int | str | None | Unset = UNSET,
625        tags: List[int | str] | None | Unset = UNSET,
626        archive_serial_number: int | None | Unset = UNSET,
627        custom_fields: List[dict[str, Any]] | None | Unset = UNSET,
628        owner: int | None | Unset = UNSET,
629        set_permissions: SetPermissions | None | Unset = UNSET,
630        remove_inbox_tags: bool | None | Unset = UNSET,
631    ) -> Document:
632        """Partially update a document (PATCH semantics).
633
634        Args:
635            id: Numeric ID of the document to update.
636            title: New document title.
637            content: OCR text content of the document.
638            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
639                :class:`~datetime.date` object.
640            correspondent: Correspondent to assign, as an ID or name.
641                Pass ``None`` to clear the correspondent.
642            document_type: Document type to assign, as an ID or name.
643                Pass ``None`` to clear the document type.
644            storage_path: Storage path to assign, as an ID or name.
645                Pass ``None`` to clear the storage path.
646            tags: Full replacement list of tags (IDs or names).
647            archive_serial_number: Archive serial number to assign.
648                Pass ``None`` to clear the archive serial number.
649            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
650            owner: Numeric user ID to assign as document owner.
651                Pass ``None`` to clear the owner.
652            set_permissions: Explicit view/change permission sets.
653                Pass ``None`` to clear all permissions (overwrite with empty).
654                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
655            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
656
657        Returns:
658            The updated :class:`~easypaperless.models.documents.Document`.
659        """
660        logger.info("Updating document id=%d", id)
661        resolver = self._core._resolver
662        payload: dict[str, Any] = {}
663
664        if not isinstance(title, Unset):
665            payload["title"] = title
666        if not isinstance(content, Unset):
667            payload["content"] = content
668        if not isinstance(created, Unset):
669            payload["created"] = self._format_date_value(created) if created is not None else None
670        if not isinstance(correspondent, Unset):
671            payload["correspondent"] = (
672                None
673                if correspondent is None
674                else await resolver.resolve("correspondents", correspondent)
675            )
676        if not isinstance(document_type, Unset):
677            payload["document_type"] = (
678                None
679                if document_type is None
680                else await resolver.resolve("document_types", document_type)
681            )
682        if not isinstance(storage_path, Unset):
683            payload["storage_path"] = (
684                None
685                if storage_path is None
686                else await resolver.resolve("storage_paths", storage_path)
687            )
688        if not isinstance(tags, Unset):
689            payload["tags"] = await resolver.resolve_list("tags", tags or [])
690        if not isinstance(archive_serial_number, Unset):
691            payload["archive_serial_number"] = archive_serial_number
692        if not isinstance(custom_fields, Unset):
693            payload["custom_fields"] = custom_fields
694        if not isinstance(owner, Unset):
695            payload["owner"] = owner
696        if not isinstance(set_permissions, Unset):
697            payload["set_permissions"] = (
698                SetPermissions().model_dump()
699                if set_permissions is None
700                else set_permissions.model_dump()
701            )
702        if not isinstance(remove_inbox_tags, Unset):
703            payload["remove_inbox_tags"] = remove_inbox_tags
704
705        resp = await self._core._session.patch(f"/documents/{id}/", json=payload)
706        return Document.model_validate(resp.json())

Partially update a document (PATCH semantics).

Arguments:
  • id: Numeric ID of the document to update.
  • title: New document title.
  • content: OCR text content of the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear the correspondent.
  • document_type: Document type to assign, as an ID or name. Pass None to clear the document type.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear the storage path.
  • tags: Full replacement list of tags (IDs or names).
  • archive_serial_number: Archive serial number to assign. Pass None to clear the archive serial number.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • owner: Numeric user ID to assign as document owner. Pass None to clear the owner.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • remove_inbox_tags: When True, removes all inbox tags from the document.
Returns:

The updated ~easypaperless.models.documents.Document.

async def delete(self, id: int) -> None:
708    async def delete(self, id: int) -> None:
709        """Permanently delete a document.
710
711        Args:
712            id: Numeric ID of the document to delete.
713
714        Raises:
715            ~easypaperless.exceptions.NotFoundError: If no document exists
716                with that ID.
717        """
718        logger.info("Deleting document id=%d", id)
719        await self._core._session.delete(f"/documents/{id}/")

Permanently delete a document.

Arguments:
  • id: Numeric ID of the document to delete.
Raises:
async def download(self, id: int, *, original: bool = False) -> bytes:
721    async def download(self, id: int, *, original: bool = False) -> bytes:
722        """Download the binary content of a document.
723
724        Args:
725            id: Numeric ID of the document to download.
726            original: If ``False`` *(default)*, returns the archived PDF
727                (``GET /documents/{id}/download/``).
728                If ``True``, returns the original uploaded file
729                (``GET /documents/{id}/download/?original=true``).
730
731        Returns:
732            Raw file bytes.
733        """
734        logger.info("Downloading document id=%d (original=%s)", id, original)
735        path = f"/documents/{id}/download/"
736        if original:
737            path += "?original=true"
738        resp = await self._core._session.get_download(path)
739        content_type = resp.headers.get("content-type", "")
740        if "text/html" in content_type or resp.content[:9].lower().startswith(b"<!doctype"):
741            raise ServerError(
742                f"Download returned an HTML page (content-type: {content_type!r}). "
743                "The server redirected to a login page even after re-attaching auth.",
744                status_code=None,
745            )
746        return resp.content

Download the binary content of a document.

Arguments:
  • id: Numeric ID of the document to download.
  • original: If False (default), returns the archived PDF (GET /documents/{id}/download/). If True, returns the original uploaded file (GET /documents/{id}/download/?original=true).
Returns:

Raw file bytes.

async def thumbnail(self, id: int) -> bytes:
748    async def thumbnail(self, id: int) -> bytes:
749        """Fetch the thumbnail image of a document.
750
751        Args:
752            id: Numeric ID of the document whose thumbnail to retrieve.
753
754        Returns:
755            Raw binary content of the thumbnail image.
756
757        Raises:
758            ~easypaperless.exceptions.NotFoundError: If no document exists
759                with that ID.
760            ~easypaperless.exceptions.ServerError: If the server returns an
761                HTML page (e.g. an auth redirect) instead of the image.
762        """
763        logger.info("Fetching thumbnail for document id=%d", id)
764        resp = await self._core._session.get_download(f"/documents/{id}/thumb/")
765        content_type = resp.headers.get("content-type", "")
766        if "text/html" in content_type or resp.content[:9].lower().startswith(b"<!doctype"):
767            raise ServerError(
768                f"Thumbnail returned an HTML page (content-type: {content_type!r}). "
769                "The server redirected to a login page even after re-attaching auth.",
770                status_code=None,
771            )
772        return resp.content

Fetch the thumbnail image of a document.

Arguments:
  • id: Numeric ID of the document whose thumbnail to retrieve.
Returns:

Raw binary content of the thumbnail image.

Raises:
async def upload( self, file: str | pathlib._local.Path, *, title: str | easypaperless.Unset = UNSET, created: datetime.date | str | None = None, correspondent: int | str | None | easypaperless.Unset = UNSET, document_type: int | str | None | easypaperless.Unset = UNSET, storage_path: int | str | None | easypaperless.Unset = UNSET, tags: Optional[List[Union[str, int]]] = None, archive_serial_number: int | None | easypaperless.Unset = UNSET, custom_fields: Optional[List[dict[str, Any]]] = None, wait: bool = False, poll_interval: float | None = None, poll_timeout: float | None = None) -> str | easypaperless.Document:
774    async def upload(
775        self,
776        file: str | Path,
777        *,
778        title: str | Unset = UNSET,
779        created: date | str | None = None,
780        correspondent: int | str | None | Unset = UNSET,
781        document_type: int | str | None | Unset = UNSET,
782        storage_path: int | str | None | Unset = UNSET,
783        tags: List[int | str] | None = None,
784        archive_serial_number: int | None | Unset = UNSET,
785        custom_fields: List[dict[str, Any]] | None = None,
786        wait: bool = False,
787        poll_interval: float | None = None,
788        poll_timeout: float | None = None,
789    ) -> str | Document:
790        """Upload a document to paperless-ngx.
791
792        Args:
793            file: Path to the file to upload.
794            title: Title to assign to the document.
795            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
796                :class:`~datetime.date` object.
797            correspondent: Correspondent to assign, as an ID or name.
798            document_type: Document type to assign, as an ID or name.
799            storage_path: Storage path to assign, as an ID or name.
800            tags: Tags to assign, as IDs or names.
801            archive_serial_number: Archive serial number to assign.
802            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
803            wait: If ``False`` *(default)*, returns immediately with the task ID.
804                If ``True``, polls until processing completes.
805            poll_interval: Seconds between task-status checks while waiting for
806                processing to complete (requires ``wait=True``). Overrides the
807                client-level default. When omitted, falls back to the client-level
808                ``poll_interval`` (``2.0`` s unless changed at construction).
809            poll_timeout: Maximum seconds to wait before raising
810                :exc:`~easypaperless.exceptions.TaskTimeoutError` (requires
811                ``wait=True``). Overrides the client-level default. When omitted,
812                falls back to the client-level ``poll_timeout`` (``60.0`` s unless
813                changed at construction).
814
815        Returns:
816            The Celery task ID string when ``wait=False``, or the fully
817            processed :class:`~easypaperless.models.documents.Document`
818            when ``wait=True``.
819
820        Raises:
821            ~easypaperless.exceptions.UploadError: If processing fails.
822            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
823        """
824        resolver = self._core._resolver
825        file_path = Path(file)
826        file_bytes = file_path.read_bytes()
827        logger.info("Uploading %r (%d bytes)", file_path.name, len(file_bytes))
828
829        data: dict[str, Any] = {}
830        if not isinstance(title, Unset):
831            data["title"] = title
832        if created is not None:
833            data["created"] = self._format_date_value(created)
834        if not isinstance(correspondent, Unset) and correspondent is not None:
835            data["correspondent"] = await resolver.resolve("correspondents", correspondent)
836        if not isinstance(document_type, Unset) and document_type is not None:
837            data["document_type"] = await resolver.resolve("document_types", document_type)
838        if not isinstance(storage_path, Unset) and storage_path is not None:
839            data["storage_path"] = await resolver.resolve("storage_paths", storage_path)
840        if tags is not None:
841            resolved = await resolver.resolve_list("tags", tags)
842            data["tags"] = resolved
843        if not isinstance(archive_serial_number, Unset) and archive_serial_number is not None:
844            data["archive_serial_number"] = archive_serial_number
845        if custom_fields is not None:
846            data["custom_fields"] = json.dumps(custom_fields)
847
848        files = {"document": (file_path.name, file_bytes)}
849        resp = await self._core._session.post("/documents/post_document/", data=data, files=files)
850        task_id: str = resp.text.strip('"')
851        logger.debug("Upload accepted, task_id=%r", task_id)
852
853        if not wait:
854            return task_id
855
856        interval = poll_interval if poll_interval is not None else self._core._poll_interval
857        timeout = poll_timeout if poll_timeout is not None else self._core._poll_timeout
858        return await self._poll_task(task_id, poll_interval=interval, poll_timeout=timeout)

Upload a document to paperless-ngx.

Arguments:
  • file: Path to the file to upload.
  • title: Title to assign to the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name.
  • document_type: Document type to assign, as an ID or name.
  • storage_path: Storage path to assign, as an ID or name.
  • tags: Tags to assign, as IDs or names.
  • archive_serial_number: Archive serial number to assign.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • wait: If False (default), returns immediately with the task ID. If True, polls until processing completes.
  • poll_interval: Seconds between task-status checks while waiting for processing to complete (requires wait=True). Overrides the client-level default. When omitted, falls back to the client-level poll_interval (2.0 s unless changed at construction).
  • poll_timeout: Maximum seconds to wait before raising ~easypaperless.exceptions.TaskTimeoutError (requires wait=True). Overrides the client-level default. When omitted, falls back to the client-level poll_timeout (60.0 s unless changed at construction).
Returns:

The Celery task ID string when wait=False, or the fully processed ~easypaperless.models.documents.Document when wait=True.

Raises:
async def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
913    async def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
914        """Add a tag to multiple documents in a single request.
915
916        Args:
917            document_ids: List of document IDs to tag.
918            tag: Tag to add, as an ID or name.
919        """
920        logger.info("Bulk adding tag %r to %d documents", tag, len(document_ids))
921        tag_id = await self._core._resolver.resolve("tags", tag)
922        await self._bulk_edit(document_ids, "add_tag", tag=tag_id)

Add a tag to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to tag.
  • tag: Tag to add, as an ID or name.
async def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
924    async def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
925        """Remove a tag from multiple documents in a single request.
926
927        Args:
928            document_ids: List of document IDs to un-tag.
929            tag: Tag to remove, as an ID or name.
930        """
931        logger.info("Bulk removing tag %r from %d documents", tag, len(document_ids))
932        tag_id = await self._core._resolver.resolve("tags", tag)
933        await self._bulk_edit(document_ids, "remove_tag", tag=tag_id)

Remove a tag from multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to un-tag.
  • tag: Tag to remove, as an ID or name.
async def bulk_modify_tags( self, document_ids: List[int], *, add_tags: Optional[List[Union[str, int]]] = None, remove_tags: Optional[List[Union[str, int]]] = None) -> None:
935    async def bulk_modify_tags(
936        self,
937        document_ids: List[int],
938        *,
939        add_tags: List[int | str] | None = None,
940        remove_tags: List[int | str] | None = None,
941    ) -> None:
942        """Add and/or remove tags on multiple documents atomically.
943
944        Args:
945            document_ids: List of document IDs to modify.
946            add_tags: Tags to add, as IDs or names.
947            remove_tags: Tags to remove, as IDs or names.
948        """
949        logger.info("Bulk modifying tags on %d documents", len(document_ids))
950        resolver = self._core._resolver
951        add_ids = await resolver.resolve_list("tags", add_tags or [])
952        remove_ids = await resolver.resolve_list("tags", remove_tags or [])
953        await self._bulk_edit(document_ids, "modify_tags", add_tags=add_ids, remove_tags=remove_ids)

Add and/or remove tags on multiple documents atomically.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_tags: Tags to add, as IDs or names.
  • remove_tags: Tags to remove, as IDs or names.
async def bulk_delete(self, document_ids: List[int]) -> None:
955    async def bulk_delete(self, document_ids: List[int]) -> None:
956        """Permanently delete multiple documents in a single request.
957
958        Args:
959            document_ids: List of document IDs to delete.
960        """
961        logger.info("Bulk deleting %d documents", len(document_ids))
962        await self._bulk_edit(document_ids, "delete")

Permanently delete multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to delete.
async def bulk_set_correspondent(self, document_ids: List[int], correspondent: int | str | None) -> None:
964    async def bulk_set_correspondent(
965        self, document_ids: List[int], correspondent: int | str | None
966    ) -> None:
967        """Assign a correspondent to multiple documents in a single request.
968
969        Args:
970            document_ids: List of document IDs to modify.
971            correspondent: Correspondent to assign, as an ID or name.
972                Pass ``None`` to clear.
973        """
974        logger.info(
975            "Bulk setting correspondent %r on %d documents", correspondent, len(document_ids)
976        )
977        cor_id: int | None = None
978        if correspondent is not None:
979            cor_id = await self._core._resolver.resolve("correspondents", correspondent)
980        await self._bulk_edit(document_ids, "set_correspondent", correspondent=cor_id)

Assign a correspondent to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear.
async def bulk_set_document_type(self, document_ids: List[int], document_type: int | str | None) -> None:
982    async def bulk_set_document_type(
983        self, document_ids: List[int], document_type: int | str | None
984    ) -> None:
985        """Assign a document type to multiple documents in a single request.
986
987        Args:
988            document_ids: List of document IDs to modify.
989            document_type: Document type to assign, as an ID or name.
990                Pass ``None`` to clear.
991        """
992        logger.info(
993            "Bulk setting document type %r on %d documents", document_type, len(document_ids)
994        )
995        dt_id: int | None = None
996        if document_type is not None:
997            dt_id = await self._core._resolver.resolve("document_types", document_type)
998        await self._bulk_edit(document_ids, "set_document_type", document_type=dt_id)

Assign a document type to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • document_type: Document type to assign, as an ID or name. Pass None to clear.
async def bulk_set_storage_path(self, document_ids: List[int], storage_path: int | str | None) -> None:
1000    async def bulk_set_storage_path(
1001        self, document_ids: List[int], storage_path: int | str | None
1002    ) -> None:
1003        """Assign a storage path to multiple documents in a single request.
1004
1005        Args:
1006            document_ids: List of document IDs to modify.
1007            storage_path: Storage path to assign, as an ID or name.
1008                Pass ``None`` to clear.
1009        """
1010        logger.info("Bulk setting storage path %r on %d documents", storage_path, len(document_ids))
1011        sp_id: int | None = None
1012        if storage_path is not None:
1013            sp_id = await self._core._resolver.resolve("storage_paths", storage_path)
1014        await self._bulk_edit(document_ids, "set_storage_path", storage_path=sp_id)

Assign a storage path to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear.
async def bulk_modify_custom_fields( self, document_ids: List[int], *, add_fields: Optional[List[dict[str, Any]]] = None, remove_fields: Optional[List[int]] = None) -> None:
1016    async def bulk_modify_custom_fields(
1017        self,
1018        document_ids: List[int],
1019        *,
1020        add_fields: List[dict[str, Any]] | None = None,
1021        remove_fields: List[int] | None = None,
1022    ) -> None:
1023        """Add and/or remove custom field values on multiple documents.
1024
1025        Args:
1026            document_ids: List of document IDs to modify.
1027            add_fields: Custom-field value dicts to add.
1028            remove_fields: Custom-field IDs whose values should be removed.
1029        """
1030        logger.info("Bulk modifying custom fields on %d documents", len(document_ids))
1031        await self._bulk_edit(
1032            document_ids,
1033            "modify_custom_fields",
1034            add_custom_fields=add_fields or [],
1035            remove_custom_fields=remove_fields or [],
1036        )

Add and/or remove custom field values on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_fields: Custom-field value dicts to add.
  • remove_fields: Custom-field IDs whose values should be removed.
async def bulk_set_permissions( self, document_ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
1038    async def bulk_set_permissions(
1039        self,
1040        document_ids: List[int],
1041        *,
1042        set_permissions: SetPermissions | Unset = UNSET,
1043        owner: int | None | Unset = UNSET,
1044        merge: bool = False,
1045    ) -> None:
1046        """Set permissions and/or owner on multiple documents.
1047
1048        Args:
1049            document_ids: List of document IDs to modify.
1050            set_permissions: Explicit view/change permission sets.
1051                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
1052            owner: Numeric user ID to assign as document owner.
1053                Pass ``None`` to clear the owner.
1054                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
1055            merge: When ``True``, new permissions are merged with existing ones.
1056        """
1057        logger.info("Bulk setting permissions on %d documents", len(document_ids))
1058        params: dict[str, Any] = {"merge": merge}
1059        if not isinstance(set_permissions, Unset):
1060            params["set_permissions"] = set_permissions.model_dump()
1061        if not isinstance(owner, Unset):
1062            params["owner"] = owner
1063        await self._bulk_edit(document_ids, "set_permissions", **params)

Set permissions and/or owner on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as document owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
async def bulk_download( self, document_ids: List[int], *, content: Literal['archive', 'originals', 'both'] = 'archive', compression: Literal['none', 'deflated', 'bzip2', 'lzma'] = 'none', follow_formatting: bool = False) -> bytes:
1065    async def bulk_download(
1066        self,
1067        document_ids: List[int],
1068        *,
1069        content: Literal["archive", "originals", "both"] = "archive",
1070        compression: Literal["none", "deflated", "bzip2", "lzma"] = "none",
1071        follow_formatting: bool = False,
1072    ) -> bytes:
1073        """Download multiple documents as a single ZIP archive.
1074
1075        Args:
1076            document_ids: List of document IDs to include in the ZIP.
1077            content: File variant to include.  One of ``"archive"`` *(default)*,
1078                ``"originals"``, or ``"both"``.
1079            compression: ZIP compression algorithm.  One of ``"none"`` *(default)*,
1080                ``"deflated"``, ``"bzip2"``, or ``"lzma"``.
1081            follow_formatting: When ``True``, filenames inside the ZIP follow
1082                the storage path formatting configured in paperless-ngx.
1083                Default: ``False``.
1084
1085        Returns:
1086            Raw bytes of the ZIP archive.
1087        """
1088        logger.info(
1089            "Bulk downloading %d documents (content=%s, compression=%s)",
1090            len(document_ids),
1091            content,
1092            compression,
1093        )
1094        payload: dict[str, Any] = {
1095            "documents": document_ids,
1096            "content": content,
1097            "compression": compression,
1098            "follow_formatting": follow_formatting,
1099        }
1100        resp = await self._core._session.post("/documents/bulk_download/", json=payload)
1101        return resp.content

Download multiple documents as a single ZIP archive.

Arguments:
  • document_ids: List of document IDs to include in the ZIP.
  • content: File variant to include. One of "archive" (default), "originals", or "both".
  • compression: ZIP compression algorithm. One of "none" (default), "deflated", "bzip2", or "lzma".
  • follow_formatting: When True, filenames inside the ZIP follow the storage path formatting configured in paperless-ngx. Default: False.
Returns:

Raw bytes of the ZIP archive.

class NotesResource:
 44class NotesResource:
 45    """Accessor for document notes: ``client.documents.notes``."""
 46
 47    def __init__(self, core: _ClientCore) -> None:
 48        self._core = core
 49
 50    async def list(
 51        self,
 52        document_id: int,
 53        *,
 54        page: int | None = None,
 55        page_size: int | None = None,
 56    ) -> PagedResult[DocumentNote]:
 57        """Fetch notes attached to a document.
 58
 59        When ``page`` is ``None`` (the default), all pages are fetched
 60        automatically and ``next`` / ``previous`` in the returned
 61        :class:`~easypaperless.models.paged_result.PagedResult` are always
 62        ``None``.  When ``page`` is set to a specific integer, only that one
 63        page is fetched and ``next`` / ``previous`` contain the raw API values.
 64
 65        Args:
 66            document_id: Numeric ID of the document whose notes to retrieve.
 67            page: Return only this specific page (1-based).
 68            page_size: Number of results per page.
 69
 70        Returns:
 71            :class:`~easypaperless.models.paged_result.PagedResult` of
 72            :class:`~easypaperless.models.documents.DocumentNote` objects,
 73            ordered by creation time.
 74
 75        Raises:
 76            ~easypaperless.exceptions.NotFoundError: If no document exists
 77                with that ID.
 78        """
 79        logger.info("Listing notes for document id=%d", document_id)
 80        path = f"/documents/{document_id}/notes/"
 81        params: dict[str, Any] = {}
 82        if page_size is not None:
 83            params["page_size"] = page_size
 84        if page is not None:
 85            params["page"] = page
 86
 87        resp = await self._core._session.get(path, params=params or None)
 88        data = resp.json()
 89
 90        if isinstance(data, list):
 91            # The paperless-ngx notes endpoint returns a plain JSON array rather
 92            # than a paginated envelope.  Build a synthetic PagedResult so callers
 93            # always receive a consistent return type regardless of API version.
 94            notes = [DocumentNote.model_validate(item) for item in data]
 95            note_ids = [n.id for n in notes if n.id is not None]
 96            all_ids: list[int] | None = note_ids if note_ids else None
 97            return PagedResult(
 98                count=len(notes),
 99                next=None,
100                previous=None,
101                all=all_ids,
102                results=notes,
103            )
104
105        # Paginated dict envelope — forward-compatible with potential future API changes.
106        items: list[Any] = list(data.get("results", []))
107        count: int = data.get("count", 0)
108        page_all_ids: list[int] | None = data.get("all")
109
110        if page is None:
111            next_url: str | None = data.get("next")
112            while next_url:
113                next_url = self._core._session._normalise_next_url(next_url)
114                page_resp = await self._core._session.get(next_url)
115                page_data = page_resp.json()
116                items.extend(page_data.get("results", []))
117                next_url = page_data.get("next")
118            return PagedResult(
119                count=count,
120                next=None,
121                previous=None,
122                all=page_all_ids,
123                results=[DocumentNote.model_validate(item) for item in items],
124            )
125
126        return cast(
127            PagedResult[DocumentNote],
128            PagedResult(
129                count=count,
130                next=data.get("next"),
131                previous=data.get("previous"),
132                all=page_all_ids,
133                results=[DocumentNote.model_validate(item) for item in items],
134            ),
135        )
136
137    async def create(self, document_id: int, *, note: str) -> DocumentNote:
138        """Create a new note on a document.
139
140        Args:
141            document_id: Numeric ID of the document to annotate.
142            note: Text content of the note.
143
144        Returns:
145            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
146
147        Raises:
148            ~easypaperless.exceptions.NotFoundError: If no document exists
149                with that ID.
150        """
151        logger.info("Creating note for document id=%d", document_id)
152        resp = await self._core._session.post(
153            f"/documents/{document_id}/notes/",
154            json={"note": note},
155        )
156        data = resp.json()
157        if isinstance(data, list):
158            return DocumentNote.model_validate(data[-1])
159        return DocumentNote.model_validate(data)
160
161    async def delete(self, document_id: int, note_id: int) -> None:
162        """Delete a note from a document.
163
164        Args:
165            document_id: Numeric ID of the document that owns the note.
166            note_id: Numeric ID of the note to delete.
167
168        Raises:
169            ~easypaperless.exceptions.NotFoundError: If no document or note
170                exists with the given IDs.
171        """
172        logger.info("Deleting note id=%d from document id=%d", note_id, document_id)
173        await self._core._session.delete(f"/documents/{document_id}/notes/", params={"id": note_id})

Accessor for document notes: client.documents.notes.

NotesResource(core: easypaperless.client._ClientCore)
47    def __init__(self, core: _ClientCore) -> None:
48        self._core = core
async def list( self, document_id: int, *, page: int | None = None, page_size: int | None = None) -> easypaperless.PagedResult[DocumentNote]:
 50    async def list(
 51        self,
 52        document_id: int,
 53        *,
 54        page: int | None = None,
 55        page_size: int | None = None,
 56    ) -> PagedResult[DocumentNote]:
 57        """Fetch notes attached to a document.
 58
 59        When ``page`` is ``None`` (the default), all pages are fetched
 60        automatically and ``next`` / ``previous`` in the returned
 61        :class:`~easypaperless.models.paged_result.PagedResult` are always
 62        ``None``.  When ``page`` is set to a specific integer, only that one
 63        page is fetched and ``next`` / ``previous`` contain the raw API values.
 64
 65        Args:
 66            document_id: Numeric ID of the document whose notes to retrieve.
 67            page: Return only this specific page (1-based).
 68            page_size: Number of results per page.
 69
 70        Returns:
 71            :class:`~easypaperless.models.paged_result.PagedResult` of
 72            :class:`~easypaperless.models.documents.DocumentNote` objects,
 73            ordered by creation time.
 74
 75        Raises:
 76            ~easypaperless.exceptions.NotFoundError: If no document exists
 77                with that ID.
 78        """
 79        logger.info("Listing notes for document id=%d", document_id)
 80        path = f"/documents/{document_id}/notes/"
 81        params: dict[str, Any] = {}
 82        if page_size is not None:
 83            params["page_size"] = page_size
 84        if page is not None:
 85            params["page"] = page
 86
 87        resp = await self._core._session.get(path, params=params or None)
 88        data = resp.json()
 89
 90        if isinstance(data, list):
 91            # The paperless-ngx notes endpoint returns a plain JSON array rather
 92            # than a paginated envelope.  Build a synthetic PagedResult so callers
 93            # always receive a consistent return type regardless of API version.
 94            notes = [DocumentNote.model_validate(item) for item in data]
 95            note_ids = [n.id for n in notes if n.id is not None]
 96            all_ids: list[int] | None = note_ids if note_ids else None
 97            return PagedResult(
 98                count=len(notes),
 99                next=None,
100                previous=None,
101                all=all_ids,
102                results=notes,
103            )
104
105        # Paginated dict envelope — forward-compatible with potential future API changes.
106        items: list[Any] = list(data.get("results", []))
107        count: int = data.get("count", 0)
108        page_all_ids: list[int] | None = data.get("all")
109
110        if page is None:
111            next_url: str | None = data.get("next")
112            while next_url:
113                next_url = self._core._session._normalise_next_url(next_url)
114                page_resp = await self._core._session.get(next_url)
115                page_data = page_resp.json()
116                items.extend(page_data.get("results", []))
117                next_url = page_data.get("next")
118            return PagedResult(
119                count=count,
120                next=None,
121                previous=None,
122                all=page_all_ids,
123                results=[DocumentNote.model_validate(item) for item in items],
124            )
125
126        return cast(
127            PagedResult[DocumentNote],
128            PagedResult(
129                count=count,
130                next=data.get("next"),
131                previous=data.get("previous"),
132                all=page_all_ids,
133                results=[DocumentNote.model_validate(item) for item in items],
134            ),
135        )

Fetch notes attached to a document.

When page is None (the default), all pages are fetched automatically and next / previous in the returned ~easypaperless.models.paged_result.PagedResult are always None. When page is set to a specific integer, only that one page is fetched and next / previous contain the raw API values.

Arguments:
  • document_id: Numeric ID of the document whose notes to retrieve.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.DocumentNote objects, ordered by creation time.

Raises:
async def create( self, document_id: int, *, note: str) -> easypaperless.DocumentNote:
137    async def create(self, document_id: int, *, note: str) -> DocumentNote:
138        """Create a new note on a document.
139
140        Args:
141            document_id: Numeric ID of the document to annotate.
142            note: Text content of the note.
143
144        Returns:
145            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
146
147        Raises:
148            ~easypaperless.exceptions.NotFoundError: If no document exists
149                with that ID.
150        """
151        logger.info("Creating note for document id=%d", document_id)
152        resp = await self._core._session.post(
153            f"/documents/{document_id}/notes/",
154            json={"note": note},
155        )
156        data = resp.json()
157        if isinstance(data, list):
158            return DocumentNote.model_validate(data[-1])
159        return DocumentNote.model_validate(data)

Create a new note on a document.

Arguments:
  • document_id: Numeric ID of the document to annotate.
  • note: Text content of the note.
Returns:

The newly created ~easypaperless.models.documents.DocumentNote.

Raises:
async def delete(self, document_id: int, note_id: int) -> None:
161    async def delete(self, document_id: int, note_id: int) -> None:
162        """Delete a note from a document.
163
164        Args:
165            document_id: Numeric ID of the document that owns the note.
166            note_id: Numeric ID of the note to delete.
167
168        Raises:
169            ~easypaperless.exceptions.NotFoundError: If no document or note
170                exists with the given IDs.
171        """
172        logger.info("Deleting note id=%d from document id=%d", note_id, document_id)
173        await self._core._session.delete(f"/documents/{document_id}/notes/", params={"id": note_id})

Delete a note from a document.

Arguments:
  • document_id: Numeric ID of the document that owns the note.
  • note_id: Numeric ID of the note to delete.
Raises:
class StoragePathsResource:
 21class StoragePathsResource:
 22    """Accessor for storage paths: ``client.storage_paths``."""
 23
 24    def __init__(self, core: _ClientCore) -> None:
 25        self._core = core
 26
 27    async def list(
 28        self,
 29        *,
 30        ids: List[int] | None = None,
 31        name_contains: str | None = None,
 32        name_exact: str | None = None,
 33        path_contains: str | None = None,
 34        path_exact: str | None = None,
 35        page: int | None = None,
 36        page_size: int | None = None,
 37        ordering: str | None = None,
 38        descending: bool = False,
 39    ) -> PagedResult[StoragePath]:
 40        """Return storage paths defined in paperless-ngx.
 41
 42        When ``page`` is ``None`` (the default), all pages are fetched
 43        automatically and ``next`` / ``previous`` in the result are always
 44        ``None``.  When ``page`` is set, only that page is fetched and
 45        ``next`` / ``previous`` reflect the raw API values.
 46
 47        Args:
 48            ids: Return only storage paths whose ID is in this list.
 49            name_contains: Case-insensitive substring filter on name.
 50            name_exact: Case-insensitive exact match on name.
 51            path_contains: Case-insensitive substring filter on path template.
 52            path_exact: Case-insensitive exact match on path template.
 53            page: Return only this specific page (1-based).
 54            page_size: Number of results per page.
 55            ordering: Field to sort by.
 56            descending: When ``True``, reverses the sort direction.
 57
 58        Returns:
 59            :class:`~easypaperless.models.paged_result.PagedResult` of
 60            :class:`~easypaperless.models.storage_paths.StoragePath` objects.
 61        """
 62        logger.info("Listing storage paths")
 63        params: dict[str, Any] = {}
 64        if ids is not None:
 65            params["id__in"] = ",".join(str(i) for i in ids)
 66        if name_contains is not None:
 67            params["name__icontains"] = name_contains
 68        if name_exact is not None:
 69            params["name__iexact"] = name_exact
 70        if path_contains is not None:
 71            params["path__icontains"] = path_contains
 72        if path_exact is not None:
 73            params["path__iexact"] = path_exact
 74        if page is not None:
 75            params["page"] = page
 76        if page_size is not None:
 77            params["page_size"] = page_size
 78        if ordering is not None:
 79            params["ordering"] = f"-{ordering}" if descending else ordering
 80        return cast(
 81            PagedResult[StoragePath],
 82            await self._core._list_resource("storage_paths", StoragePath, params or None),
 83        )
 84
 85    async def get(self, id: int) -> StoragePath:
 86        """Fetch a single storage path by its ID.
 87
 88        Args:
 89            id: Numeric storage-path ID.
 90
 91        Returns:
 92            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
 93
 94        Raises:
 95            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
 96        """
 97        logger.info("Getting storage path id=%d", id)
 98        return cast(StoragePath, await self._core._get_resource("storage_paths", id, StoragePath))
 99
100    async def create(
101        self,
102        *,
103        name: str,
104        path: str | Unset = UNSET,
105        match: str | Unset = UNSET,
106        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
107        is_insensitive: bool = True,
108        owner: int | None | Unset = UNSET,
109        set_permissions: SetPermissions | None | Unset = UNSET,
110    ) -> StoragePath:
111        """Create a new storage path.
112
113        Args:
114            name: Storage-path name. Must be unique.
115            path: Template string for the archive file path.
116            match: Auto-matching pattern.
117            matching_algorithm: Controls how ``match`` is applied.
118                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
119                regular-expression matching.
120            is_insensitive: When ``True``, ``match`` is case-insensitive.
121                Defaults to ``True``, matching the paperless-ngx API default.
122            owner: Numeric user ID to assign as owner.
123            set_permissions: Explicit view/change permission sets.
124                Pass ``None`` to create with empty permissions.
125
126        Returns:
127            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
128        """
129        logger.info("Creating storage path name=%r", name)
130        return cast(
131            StoragePath,
132            await self._core._create_resource(
133                "storage_paths",
134                StoragePath,
135                owner=owner,
136                set_permissions=set_permissions,
137                name=name,
138                path=path,
139                match=match,
140                matching_algorithm=matching_algorithm,
141                is_insensitive=is_insensitive,
142            ),
143        )
144
145    async def update(
146        self,
147        id: int,
148        *,
149        name: str | Unset = UNSET,
150        path: str | Unset = UNSET,
151        match: str | Unset = UNSET,
152        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
153        is_insensitive: bool | Unset = UNSET,
154        owner: int | None | Unset = UNSET,
155        set_permissions: SetPermissions | None | Unset = UNSET,
156    ) -> StoragePath:
157        """Partially update a storage path (PATCH semantics).
158
159        Args:
160            id: Numeric ID of the storage path to update.
161            name: Storage-path name.
162            path: Template string for the archive file path.
163            match: Auto-matching pattern.
164            matching_algorithm: Controls how ``match`` is applied.
165                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
166                regular-expression matching.
167            is_insensitive: When ``True``, ``match`` is case-insensitive.
168            owner: Numeric user ID to assign as owner.
169                Pass ``None`` to clear the owner.
170                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
171            set_permissions: Explicit view/change permission sets.
172                Pass ``None`` to clear all permissions (overwrite with empty).
173                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
174
175        Returns:
176            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
177        """
178        logger.info("Updating storage path id=%d", id)
179        return cast(
180            StoragePath,
181            await self._core._update_resource(
182                "storage_paths",
183                id,
184                StoragePath,
185                name=name,
186                path=path,
187                match=match,
188                matching_algorithm=matching_algorithm,
189                is_insensitive=is_insensitive,
190                owner=owner,
191                set_permissions=set_permissions,
192            ),
193        )
194
195    async def delete(self, id: int) -> None:
196        """Delete a storage path.
197
198        Args:
199            id: Numeric ID of the storage path to delete.
200
201        Raises:
202            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
203        """
204        logger.info("Deleting storage path id=%d", id)
205        await self._core._delete_resource("storage_paths", id)
206
207    async def bulk_delete(self, ids: List[int]) -> None:
208        """Permanently delete multiple storage paths in a single request.
209
210        Args:
211            ids: List of storage path IDs to delete.
212        """
213        logger.info("Bulk deleting %d storage paths", len(ids))
214        await self._core._bulk_edit_objects("storage_paths", ids, "delete")
215
216    async def bulk_set_permissions(
217        self,
218        ids: List[int],
219        *,
220        set_permissions: SetPermissions | Unset = UNSET,
221        owner: int | None | Unset = UNSET,
222        merge: bool = False,
223    ) -> None:
224        """Set permissions and/or owner on multiple storage paths.
225
226        Args:
227            ids: List of storage path IDs to modify.
228            set_permissions: Explicit view/change permission sets.
229                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
230            owner: Numeric user ID to assign as owner.
231                Pass ``None`` to clear the owner.
232                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
233            merge: When ``True``, new permissions are merged with existing ones.
234        """
235        logger.info("Bulk setting permissions on %d storage paths", len(ids))
236        params: dict[str, Any] = {"merge": merge}
237        if not isinstance(set_permissions, Unset):
238            params["permissions"] = set_permissions.model_dump()
239        if not isinstance(owner, Unset):
240            params["owner"] = owner
241        await self._core._bulk_edit_objects("storage_paths", ids, "set_permissions", **params)

Accessor for storage paths: client.storage_paths.

StoragePathsResource(core: easypaperless.client._ClientCore)
24    def __init__(self, core: _ClientCore) -> None:
25        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, path_contains: str | None = None, path_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[StoragePath]:
27    async def list(
28        self,
29        *,
30        ids: List[int] | None = None,
31        name_contains: str | None = None,
32        name_exact: str | None = None,
33        path_contains: str | None = None,
34        path_exact: str | None = None,
35        page: int | None = None,
36        page_size: int | None = None,
37        ordering: str | None = None,
38        descending: bool = False,
39    ) -> PagedResult[StoragePath]:
40        """Return storage paths defined in paperless-ngx.
41
42        When ``page`` is ``None`` (the default), all pages are fetched
43        automatically and ``next`` / ``previous`` in the result are always
44        ``None``.  When ``page`` is set, only that page is fetched and
45        ``next`` / ``previous`` reflect the raw API values.
46
47        Args:
48            ids: Return only storage paths whose ID is in this list.
49            name_contains: Case-insensitive substring filter on name.
50            name_exact: Case-insensitive exact match on name.
51            path_contains: Case-insensitive substring filter on path template.
52            path_exact: Case-insensitive exact match on path template.
53            page: Return only this specific page (1-based).
54            page_size: Number of results per page.
55            ordering: Field to sort by.
56            descending: When ``True``, reverses the sort direction.
57
58        Returns:
59            :class:`~easypaperless.models.paged_result.PagedResult` of
60            :class:`~easypaperless.models.storage_paths.StoragePath` objects.
61        """
62        logger.info("Listing storage paths")
63        params: dict[str, Any] = {}
64        if ids is not None:
65            params["id__in"] = ",".join(str(i) for i in ids)
66        if name_contains is not None:
67            params["name__icontains"] = name_contains
68        if name_exact is not None:
69            params["name__iexact"] = name_exact
70        if path_contains is not None:
71            params["path__icontains"] = path_contains
72        if path_exact is not None:
73            params["path__iexact"] = path_exact
74        if page is not None:
75            params["page"] = page
76        if page_size is not None:
77            params["page_size"] = page_size
78        if ordering is not None:
79            params["ordering"] = f"-{ordering}" if descending else ordering
80        return cast(
81            PagedResult[StoragePath],
82            await self._core._list_resource("storage_paths", StoragePath, params or None),
83        )

Return storage paths defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only storage paths whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • path_contains: Case-insensitive substring filter on path template.
  • path_exact: Case-insensitive exact match on path template.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.storage_paths.StoragePath objects.

async def get(self, id: int) -> easypaperless.StoragePath:
85    async def get(self, id: int) -> StoragePath:
86        """Fetch a single storage path by its ID.
87
88        Args:
89            id: Numeric storage-path ID.
90
91        Returns:
92            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
93
94        Raises:
95            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
96        """
97        logger.info("Getting storage path id=%d", id)
98        return cast(StoragePath, await self._core._get_resource("storage_paths", id, StoragePath))

Fetch a single storage path by its ID.

Arguments:
  • id: Numeric storage-path ID.
Returns:

The ~easypaperless.models.storage_paths.StoragePath with the given ID.

Raises:
async def create( self, *, name: str, path: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.StoragePath:
100    async def create(
101        self,
102        *,
103        name: str,
104        path: str | Unset = UNSET,
105        match: str | Unset = UNSET,
106        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
107        is_insensitive: bool = True,
108        owner: int | None | Unset = UNSET,
109        set_permissions: SetPermissions | None | Unset = UNSET,
110    ) -> StoragePath:
111        """Create a new storage path.
112
113        Args:
114            name: Storage-path name. Must be unique.
115            path: Template string for the archive file path.
116            match: Auto-matching pattern.
117            matching_algorithm: Controls how ``match`` is applied.
118                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
119                regular-expression matching.
120            is_insensitive: When ``True``, ``match`` is case-insensitive.
121                Defaults to ``True``, matching the paperless-ngx API default.
122            owner: Numeric user ID to assign as owner.
123            set_permissions: Explicit view/change permission sets.
124                Pass ``None`` to create with empty permissions.
125
126        Returns:
127            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
128        """
129        logger.info("Creating storage path name=%r", name)
130        return cast(
131            StoragePath,
132            await self._core._create_resource(
133                "storage_paths",
134                StoragePath,
135                owner=owner,
136                set_permissions=set_permissions,
137                name=name,
138                path=path,
139                match=match,
140                matching_algorithm=matching_algorithm,
141                is_insensitive=is_insensitive,
142            ),
143        )

Create a new storage path.

Arguments:
  • name: Storage-path name. Must be unique.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.storage_paths.StoragePath.

async def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, path: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.StoragePath:
145    async def update(
146        self,
147        id: int,
148        *,
149        name: str | Unset = UNSET,
150        path: str | Unset = UNSET,
151        match: str | Unset = UNSET,
152        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
153        is_insensitive: bool | Unset = UNSET,
154        owner: int | None | Unset = UNSET,
155        set_permissions: SetPermissions | None | Unset = UNSET,
156    ) -> StoragePath:
157        """Partially update a storage path (PATCH semantics).
158
159        Args:
160            id: Numeric ID of the storage path to update.
161            name: Storage-path name.
162            path: Template string for the archive file path.
163            match: Auto-matching pattern.
164            matching_algorithm: Controls how ``match`` is applied.
165                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
166                regular-expression matching.
167            is_insensitive: When ``True``, ``match`` is case-insensitive.
168            owner: Numeric user ID to assign as owner.
169                Pass ``None`` to clear the owner.
170                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
171            set_permissions: Explicit view/change permission sets.
172                Pass ``None`` to clear all permissions (overwrite with empty).
173                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
174
175        Returns:
176            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
177        """
178        logger.info("Updating storage path id=%d", id)
179        return cast(
180            StoragePath,
181            await self._core._update_resource(
182                "storage_paths",
183                id,
184                StoragePath,
185                name=name,
186                path=path,
187                match=match,
188                matching_algorithm=matching_algorithm,
189                is_insensitive=is_insensitive,
190                owner=owner,
191                set_permissions=set_permissions,
192            ),
193        )

Partially update a storage path (PATCH semantics).

Arguments:
  • id: Numeric ID of the storage path to update.
  • name: Storage-path name.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.storage_paths.StoragePath.

async def delete(self, id: int) -> None:
195    async def delete(self, id: int) -> None:
196        """Delete a storage path.
197
198        Args:
199            id: Numeric ID of the storage path to delete.
200
201        Raises:
202            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
203        """
204        logger.info("Deleting storage path id=%d", id)
205        await self._core._delete_resource("storage_paths", id)

Delete a storage path.

Arguments:
  • id: Numeric ID of the storage path to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
207    async def bulk_delete(self, ids: List[int]) -> None:
208        """Permanently delete multiple storage paths in a single request.
209
210        Args:
211            ids: List of storage path IDs to delete.
212        """
213        logger.info("Bulk deleting %d storage paths", len(ids))
214        await self._core._bulk_edit_objects("storage_paths", ids, "delete")

Permanently delete multiple storage paths in a single request.

Arguments:
  • ids: List of storage path IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
216    async def bulk_set_permissions(
217        self,
218        ids: List[int],
219        *,
220        set_permissions: SetPermissions | Unset = UNSET,
221        owner: int | None | Unset = UNSET,
222        merge: bool = False,
223    ) -> None:
224        """Set permissions and/or owner on multiple storage paths.
225
226        Args:
227            ids: List of storage path IDs to modify.
228            set_permissions: Explicit view/change permission sets.
229                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
230            owner: Numeric user ID to assign as owner.
231                Pass ``None`` to clear the owner.
232                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
233            merge: When ``True``, new permissions are merged with existing ones.
234        """
235        logger.info("Bulk setting permissions on %d storage paths", len(ids))
236        params: dict[str, Any] = {"merge": merge}
237        if not isinstance(set_permissions, Unset):
238            params["permissions"] = set_permissions.model_dump()
239        if not isinstance(owner, Unset):
240            params["owner"] = owner
241        await self._core._bulk_edit_objects("storage_paths", ids, "set_permissions", **params)

Set permissions and/or owner on multiple storage paths.

Arguments:
  • ids: List of storage path IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class TagsResource:
 21class TagsResource:
 22    """Accessor for tags: ``client.tags``."""
 23
 24    def __init__(self, core: _ClientCore) -> None:
 25        self._core = core
 26
 27    async def list(
 28        self,
 29        *,
 30        ids: List[int] | None = None,
 31        name_contains: str | None = None,
 32        name_exact: str | None = None,
 33        page: int | None = None,
 34        page_size: int | None = None,
 35        ordering: str | None = None,
 36        descending: bool = False,
 37    ) -> PagedResult[Tag]:
 38        """Return tags defined in paperless-ngx.
 39
 40        When ``page`` is ``None`` (the default), all pages are fetched
 41        automatically and ``next`` / ``previous`` in the result are always
 42        ``None``.  When ``page`` is set, only that page is fetched and
 43        ``next`` / ``previous`` reflect the raw API values.
 44
 45        Args:
 46            ids: Return only tags whose ID is in this list.
 47            name_contains: Case-insensitive substring filter on tag name.
 48            name_exact: Case-insensitive exact match on tag name.
 49            page: Return only this specific page (1-based).
 50            page_size: Number of results per page.
 51            ordering: Field to sort by.
 52            descending: When ``True``, reverses the sort direction.
 53
 54        Returns:
 55            :class:`~easypaperless.models.paged_result.PagedResult` of
 56            :class:`~easypaperless.models.tags.Tag` objects.
 57        """
 58        logger.info("Listing tags")
 59        params: dict[str, Any] = {}
 60        if ids is not None:
 61            params["id__in"] = ",".join(str(i) for i in ids)
 62        if name_contains is not None:
 63            params["name__icontains"] = name_contains
 64        if name_exact is not None:
 65            params["name__iexact"] = name_exact
 66        if page is not None:
 67            params["page"] = page
 68        if page_size is not None:
 69            params["page_size"] = page_size
 70        if ordering is not None:
 71            params["ordering"] = f"-{ordering}" if descending else ordering
 72        return cast(
 73            PagedResult[Tag],
 74            await self._core._list_resource("tags", Tag, params or None),
 75        )
 76
 77    async def get(self, id: int) -> Tag:
 78        """Fetch a single tag by its ID.
 79
 80        Args:
 81            id: Numeric tag ID.
 82
 83        Returns:
 84            The :class:`~easypaperless.models.tags.Tag` with the given ID.
 85
 86        Raises:
 87            ~easypaperless.exceptions.NotFoundError: If no tag exists with
 88                that ID.
 89        """
 90        logger.info("Getting tag id=%d", id)
 91        return cast(Tag, await self._core._get_resource("tags", id, Tag))
 92
 93    async def create(
 94        self,
 95        *,
 96        name: str,
 97        color: str | Unset = UNSET,
 98        is_inbox_tag: bool | Unset = UNSET,
 99        match: str | Unset = UNSET,
100        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
101        is_insensitive: bool = True,
102        parent: int | None | Unset = UNSET,
103        owner: int | None | Unset = UNSET,
104        set_permissions: SetPermissions | None | Unset = UNSET,
105    ) -> Tag:
106        """Create a new tag.
107
108        Args:
109            name: Tag name. Must be unique.
110            color: Background colour as a CSS hex string.
111            is_inbox_tag: When ``True``, newly ingested documents get this tag.
112            match: Auto-matching pattern.
113            matching_algorithm: Controls how ``match`` is applied.
114                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
115                regular-expression matching.
116            is_insensitive: When ``True``, ``match`` is case-insensitive.
117                Defaults to ``True``, matching the paperless-ngx API default.
118            parent: ID of parent tag for hierarchical trees.
119            owner: Numeric user ID to assign as owner.
120            set_permissions: Explicit view/change permission sets.
121                Pass ``None`` to create with empty permissions.
122
123        Returns:
124            The newly created :class:`~easypaperless.models.tags.Tag`.
125        """
126        logger.info("Creating tag name=%r", name)
127        return cast(
128            Tag,
129            await self._core._create_resource(
130                "tags",
131                Tag,
132                owner=owner,
133                set_permissions=set_permissions,
134                name=name,
135                color=color,
136                is_inbox_tag=is_inbox_tag,
137                match=match,
138                matching_algorithm=matching_algorithm,
139                is_insensitive=is_insensitive,
140                parent=parent,
141            ),
142        )
143
144    async def update(
145        self,
146        id: int,
147        *,
148        name: str | Unset = UNSET,
149        color: str | Unset = UNSET,
150        is_inbox_tag: bool | Unset = UNSET,
151        match: str | Unset = UNSET,
152        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
153        is_insensitive: bool | Unset = UNSET,
154        parent: int | None | Unset = UNSET,
155        owner: int | None | Unset = UNSET,
156        set_permissions: SetPermissions | None | Unset = UNSET,
157    ) -> Tag:
158        """Partially update a tag (PATCH semantics).
159
160        Args:
161            id: Numeric ID of the tag to update.
162            name: Tag name.
163            color: Background colour as a CSS hex string.
164            is_inbox_tag: When ``True``, newly ingested documents get this tag.
165            match: Auto-matching pattern.
166            matching_algorithm: Controls how ``match`` is applied.
167                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
168                regular-expression matching.
169            is_insensitive: When ``True``, ``match`` is case-insensitive.
170            parent: ID of parent tag.
171                Pass ``None`` to clear (make root tag).
172                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
173            owner: Numeric user ID to assign as owner.
174                Pass ``None`` to clear the owner.
175                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
176            set_permissions: Explicit view/change permission sets.
177                Pass ``None`` to clear all permissions (overwrite with empty).
178                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
179
180        Returns:
181            The updated :class:`~easypaperless.models.tags.Tag`.
182        """
183        logger.info("Updating tag id=%d", id)
184        return cast(
185            Tag,
186            await self._core._update_resource(
187                "tags",
188                id,
189                Tag,
190                name=name,
191                color=color,
192                is_inbox_tag=is_inbox_tag,
193                match=match,
194                matching_algorithm=matching_algorithm,
195                is_insensitive=is_insensitive,
196                parent=parent,
197                owner=owner,
198                set_permissions=set_permissions,
199            ),
200        )
201
202    async def delete(self, id: int) -> None:
203        """Delete a tag.
204
205        Args:
206            id: Numeric ID of the tag to delete.
207
208        Raises:
209            ~easypaperless.exceptions.NotFoundError: If no tag exists with
210                that ID.
211        """
212        logger.info("Deleting tag id=%d", id)
213        await self._core._delete_resource("tags", id)
214
215    async def bulk_delete(self, ids: List[int]) -> None:
216        """Permanently delete multiple tags in a single request.
217
218        Args:
219            ids: List of tag IDs to delete.
220        """
221        logger.info("Bulk deleting %d tags", len(ids))
222        await self._core._bulk_edit_objects("tags", ids, "delete")
223
224    async def bulk_set_permissions(
225        self,
226        ids: List[int],
227        *,
228        set_permissions: SetPermissions | Unset = UNSET,
229        owner: int | None | Unset = UNSET,
230        merge: bool = False,
231    ) -> None:
232        """Set permissions and/or owner on multiple tags.
233
234        Args:
235            ids: List of tag IDs to modify.
236            set_permissions: Explicit view/change permission sets.
237                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
238            owner: Numeric user ID to assign as owner.
239                Pass ``None`` to clear the owner.
240                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
241            merge: When ``True``, new permissions are merged with existing ones.
242        """
243        logger.info("Bulk setting permissions on %d tags", len(ids))
244        params: dict[str, Any] = {"merge": merge}
245        if not isinstance(set_permissions, Unset):
246            params["permissions"] = set_permissions.model_dump()
247        if not isinstance(owner, Unset):
248            params["owner"] = owner
249        await self._core._bulk_edit_objects("tags", ids, "set_permissions", **params)

Accessor for tags: client.tags.

TagsResource(core: easypaperless.client._ClientCore)
24    def __init__(self, core: _ClientCore) -> None:
25        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[Tag]:
27    async def list(
28        self,
29        *,
30        ids: List[int] | None = None,
31        name_contains: str | None = None,
32        name_exact: str | None = None,
33        page: int | None = None,
34        page_size: int | None = None,
35        ordering: str | None = None,
36        descending: bool = False,
37    ) -> PagedResult[Tag]:
38        """Return tags defined in paperless-ngx.
39
40        When ``page`` is ``None`` (the default), all pages are fetched
41        automatically and ``next`` / ``previous`` in the result are always
42        ``None``.  When ``page`` is set, only that page is fetched and
43        ``next`` / ``previous`` reflect the raw API values.
44
45        Args:
46            ids: Return only tags whose ID is in this list.
47            name_contains: Case-insensitive substring filter on tag name.
48            name_exact: Case-insensitive exact match on tag name.
49            page: Return only this specific page (1-based).
50            page_size: Number of results per page.
51            ordering: Field to sort by.
52            descending: When ``True``, reverses the sort direction.
53
54        Returns:
55            :class:`~easypaperless.models.paged_result.PagedResult` of
56            :class:`~easypaperless.models.tags.Tag` objects.
57        """
58        logger.info("Listing tags")
59        params: dict[str, Any] = {}
60        if ids is not None:
61            params["id__in"] = ",".join(str(i) for i in ids)
62        if name_contains is not None:
63            params["name__icontains"] = name_contains
64        if name_exact is not None:
65            params["name__iexact"] = name_exact
66        if page is not None:
67            params["page"] = page
68        if page_size is not None:
69            params["page_size"] = page_size
70        if ordering is not None:
71            params["ordering"] = f"-{ordering}" if descending else ordering
72        return cast(
73            PagedResult[Tag],
74            await self._core._list_resource("tags", Tag, params or None),
75        )

Return tags defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only tags whose ID is in this list.
  • name_contains: Case-insensitive substring filter on tag name.
  • name_exact: Case-insensitive exact match on tag name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.tags.Tag objects.

async def get(self, id: int) -> easypaperless.Tag:
77    async def get(self, id: int) -> Tag:
78        """Fetch a single tag by its ID.
79
80        Args:
81            id: Numeric tag ID.
82
83        Returns:
84            The :class:`~easypaperless.models.tags.Tag` with the given ID.
85
86        Raises:
87            ~easypaperless.exceptions.NotFoundError: If no tag exists with
88                that ID.
89        """
90        logger.info("Getting tag id=%d", id)
91        return cast(Tag, await self._core._get_resource("tags", id, Tag))

Fetch a single tag by its ID.

Arguments:
  • id: Numeric tag ID.
Returns:

The ~easypaperless.models.tags.Tag with the given ID.

Raises:
async def create( self, *, name: str, color: str | easypaperless.Unset = UNSET, is_inbox_tag: bool | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, parent: int | None | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Tag:
 93    async def create(
 94        self,
 95        *,
 96        name: str,
 97        color: str | Unset = UNSET,
 98        is_inbox_tag: bool | Unset = UNSET,
 99        match: str | Unset = UNSET,
100        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
101        is_insensitive: bool = True,
102        parent: int | None | Unset = UNSET,
103        owner: int | None | Unset = UNSET,
104        set_permissions: SetPermissions | None | Unset = UNSET,
105    ) -> Tag:
106        """Create a new tag.
107
108        Args:
109            name: Tag name. Must be unique.
110            color: Background colour as a CSS hex string.
111            is_inbox_tag: When ``True``, newly ingested documents get this tag.
112            match: Auto-matching pattern.
113            matching_algorithm: Controls how ``match`` is applied.
114                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
115                regular-expression matching.
116            is_insensitive: When ``True``, ``match`` is case-insensitive.
117                Defaults to ``True``, matching the paperless-ngx API default.
118            parent: ID of parent tag for hierarchical trees.
119            owner: Numeric user ID to assign as owner.
120            set_permissions: Explicit view/change permission sets.
121                Pass ``None`` to create with empty permissions.
122
123        Returns:
124            The newly created :class:`~easypaperless.models.tags.Tag`.
125        """
126        logger.info("Creating tag name=%r", name)
127        return cast(
128            Tag,
129            await self._core._create_resource(
130                "tags",
131                Tag,
132                owner=owner,
133                set_permissions=set_permissions,
134                name=name,
135                color=color,
136                is_inbox_tag=is_inbox_tag,
137                match=match,
138                matching_algorithm=matching_algorithm,
139                is_insensitive=is_insensitive,
140                parent=parent,
141            ),
142        )

Create a new tag.

Arguments:
  • name: Tag name. Must be unique.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • parent: ID of parent tag for hierarchical trees.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.tags.Tag.

async def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, color: str | easypaperless.Unset = UNSET, is_inbox_tag: bool | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, parent: int | None | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Tag:
144    async def update(
145        self,
146        id: int,
147        *,
148        name: str | Unset = UNSET,
149        color: str | Unset = UNSET,
150        is_inbox_tag: bool | Unset = UNSET,
151        match: str | Unset = UNSET,
152        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
153        is_insensitive: bool | Unset = UNSET,
154        parent: int | None | Unset = UNSET,
155        owner: int | None | Unset = UNSET,
156        set_permissions: SetPermissions | None | Unset = UNSET,
157    ) -> Tag:
158        """Partially update a tag (PATCH semantics).
159
160        Args:
161            id: Numeric ID of the tag to update.
162            name: Tag name.
163            color: Background colour as a CSS hex string.
164            is_inbox_tag: When ``True``, newly ingested documents get this tag.
165            match: Auto-matching pattern.
166            matching_algorithm: Controls how ``match`` is applied.
167                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
168                regular-expression matching.
169            is_insensitive: When ``True``, ``match`` is case-insensitive.
170            parent: ID of parent tag.
171                Pass ``None`` to clear (make root tag).
172                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
173            owner: Numeric user ID to assign as owner.
174                Pass ``None`` to clear the owner.
175                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
176            set_permissions: Explicit view/change permission sets.
177                Pass ``None`` to clear all permissions (overwrite with empty).
178                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
179
180        Returns:
181            The updated :class:`~easypaperless.models.tags.Tag`.
182        """
183        logger.info("Updating tag id=%d", id)
184        return cast(
185            Tag,
186            await self._core._update_resource(
187                "tags",
188                id,
189                Tag,
190                name=name,
191                color=color,
192                is_inbox_tag=is_inbox_tag,
193                match=match,
194                matching_algorithm=matching_algorithm,
195                is_insensitive=is_insensitive,
196                parent=parent,
197                owner=owner,
198                set_permissions=set_permissions,
199            ),
200        )

Partially update a tag (PATCH semantics).

Arguments:
  • id: Numeric ID of the tag to update.
  • name: Tag name.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • parent: ID of parent tag. Pass None to clear (make root tag). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.tags.Tag.

async def delete(self, id: int) -> None:
202    async def delete(self, id: int) -> None:
203        """Delete a tag.
204
205        Args:
206            id: Numeric ID of the tag to delete.
207
208        Raises:
209            ~easypaperless.exceptions.NotFoundError: If no tag exists with
210                that ID.
211        """
212        logger.info("Deleting tag id=%d", id)
213        await self._core._delete_resource("tags", id)

Delete a tag.

Arguments:
  • id: Numeric ID of the tag to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
215    async def bulk_delete(self, ids: List[int]) -> None:
216        """Permanently delete multiple tags in a single request.
217
218        Args:
219            ids: List of tag IDs to delete.
220        """
221        logger.info("Bulk deleting %d tags", len(ids))
222        await self._core._bulk_edit_objects("tags", ids, "delete")

Permanently delete multiple tags in a single request.

Arguments:
  • ids: List of tag IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
224    async def bulk_set_permissions(
225        self,
226        ids: List[int],
227        *,
228        set_permissions: SetPermissions | Unset = UNSET,
229        owner: int | None | Unset = UNSET,
230        merge: bool = False,
231    ) -> None:
232        """Set permissions and/or owner on multiple tags.
233
234        Args:
235            ids: List of tag IDs to modify.
236            set_permissions: Explicit view/change permission sets.
237                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
238            owner: Numeric user ID to assign as owner.
239                Pass ``None`` to clear the owner.
240                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
241            merge: When ``True``, new permissions are merged with existing ones.
242        """
243        logger.info("Bulk setting permissions on %d tags", len(ids))
244        params: dict[str, Any] = {"merge": merge}
245        if not isinstance(set_permissions, Unset):
246            params["permissions"] = set_permissions.model_dump()
247        if not isinstance(owner, Unset):
248            params["owner"] = owner
249        await self._core._bulk_edit_objects("tags", ids, "set_permissions", **params)

Set permissions and/or owner on multiple tags.

Arguments:
  • ids: List of tag IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class SyncCorrespondentsResource:
 18class SyncCorrespondentsResource:
 19    """Sync accessor for correspondents: ``client.correspondents``."""
 20
 21    def __init__(self, async_correspondents: CorrespondentsResource, run: Any) -> None:
 22        self._async_correspondents = async_correspondents
 23        self._run = run
 24
 25    def list(
 26        self,
 27        *,
 28        ids: List[int] | None = None,
 29        name_contains: str | None = None,
 30        name_exact: str | None = None,
 31        page: int | None = None,
 32        page_size: int | None = None,
 33        ordering: str | None = None,
 34        descending: bool = False,
 35    ) -> PagedResult[Correspondent]:
 36        """Return correspondents defined in paperless-ngx.
 37
 38        When ``page`` is ``None`` (the default), all pages are fetched
 39        automatically and ``next`` / ``previous`` in the result are always
 40        ``None``.  When ``page`` is set, only that page is fetched and
 41        ``next`` / ``previous`` reflect the raw API values.
 42
 43        Args:
 44            ids: Return only correspondents whose ID is in this list.
 45            name_contains: Case-insensitive substring filter on name.
 46            name_exact: Case-insensitive exact match on name.
 47            page: Return only this specific page (1-based).
 48            page_size: Number of results per page.
 49            ordering: Field to sort by.
 50            descending: When ``True``, reverses the sort direction.
 51
 52        Returns:
 53            :class:`~easypaperless.models.paged_result.PagedResult` of
 54            :class:`~easypaperless.models.correspondents.Correspondent` objects.
 55        """
 56        return cast(
 57            PagedResult[Correspondent],
 58            self._run(
 59                self._async_correspondents.list(
 60                    ids=ids,
 61                    name_contains=name_contains,
 62                    name_exact=name_exact,
 63                    page=page,
 64                    page_size=page_size,
 65                    ordering=ordering,
 66                    descending=descending,
 67                )
 68            ),
 69        )
 70
 71    def get(self, id: int) -> Correspondent:
 72        """Fetch a single correspondent by its ID.
 73
 74        Args:
 75            id: Numeric correspondent ID.
 76
 77        Returns:
 78            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
 79
 80        Raises:
 81            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
 82        """
 83        return cast(Correspondent, self._run(self._async_correspondents.get(id)))
 84
 85    def create(
 86        self,
 87        *,
 88        name: str,
 89        match: str | Unset = UNSET,
 90        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 91        is_insensitive: bool = True,
 92        owner: int | None | Unset = UNSET,
 93        set_permissions: SetPermissions | None | Unset = UNSET,
 94    ) -> Correspondent:
 95        """Create a new correspondent.
 96
 97        Args:
 98            name: Correspondent name. Must be unique.
 99            match: Auto-matching pattern.
100            matching_algorithm: Controls how ``match`` is applied.
101                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
102                regular-expression matching.
103            is_insensitive: When ``True``, ``match`` is case-insensitive.
104                Defaults to ``True``, matching the paperless-ngx API default.
105            owner: Numeric user ID to assign as owner.
106            set_permissions: Explicit view/change permission sets.
107                Pass ``None`` to create with empty permissions.
108
109        Returns:
110            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
111        """
112        return cast(
113            Correspondent,
114            self._run(
115                self._async_correspondents.create(
116                    name=name,
117                    match=match,
118                    matching_algorithm=matching_algorithm,
119                    is_insensitive=is_insensitive,
120                    owner=owner,
121                    set_permissions=set_permissions,
122                )
123            ),
124        )
125
126    def update(
127        self,
128        id: int,
129        *,
130        name: str | Unset = UNSET,
131        match: str | Unset = UNSET,
132        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
133        is_insensitive: bool | Unset = UNSET,
134        owner: int | None | Unset = UNSET,
135        set_permissions: SetPermissions | None | Unset = UNSET,
136    ) -> Correspondent:
137        """Partially update a correspondent (PATCH semantics).
138
139        Args:
140            id: Numeric ID of the correspondent to update.
141            name: Correspondent name.
142            match: Auto-matching pattern.
143            matching_algorithm: Controls how ``match`` is applied.
144                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
145                regular-expression matching.
146            is_insensitive: When ``True``, ``match`` is case-insensitive.
147            owner: Numeric user ID to assign as owner.
148                Pass ``None`` to clear the owner.
149                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
150            set_permissions: Explicit view/change permission sets.
151                Pass ``None`` to clear all permissions (overwrite with empty).
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153
154        Returns:
155            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
156        """
157        return cast(
158            Correspondent,
159            self._run(
160                self._async_correspondents.update(
161                    id,
162                    name=name,
163                    match=match,
164                    matching_algorithm=matching_algorithm,
165                    is_insensitive=is_insensitive,
166                    owner=owner,
167                    set_permissions=set_permissions,
168                )
169            ),
170        )
171
172    def delete(self, id: int) -> None:
173        """Delete a correspondent.
174
175        Args:
176            id: Numeric ID of the correspondent to delete.
177
178        Raises:
179            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
180        """
181        self._run(self._async_correspondents.delete(id))
182
183    def bulk_delete(self, ids: List[int]) -> None:
184        """Permanently delete multiple correspondents in a single request.
185
186        Args:
187            ids: List of correspondent IDs to delete.
188        """
189        self._run(self._async_correspondents.bulk_delete(ids))
190
191    def bulk_set_permissions(
192        self,
193        ids: List[int],
194        *,
195        set_permissions: SetPermissions | Unset = UNSET,
196        owner: int | None | Unset = UNSET,
197        merge: bool = False,
198    ) -> None:
199        """Set permissions and/or owner on multiple correspondents.
200
201        Args:
202            ids: List of correspondent IDs to modify.
203            set_permissions: Explicit view/change permission sets.
204                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
205            owner: Numeric user ID to assign as owner.
206                Pass ``None`` to clear the owner.
207                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
208            merge: When ``True``, new permissions are merged with existing ones.
209        """
210        self._run(
211            self._async_correspondents.bulk_set_permissions(
212                ids, set_permissions=set_permissions, owner=owner, merge=merge
213            )
214        )

Sync accessor for correspondents: client.correspondents.

SyncCorrespondentsResource( async_correspondents: CorrespondentsResource, run: Any)
21    def __init__(self, async_correspondents: CorrespondentsResource, run: Any) -> None:
22        self._async_correspondents = async_correspondents
23        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[Correspondent]:
25    def list(
26        self,
27        *,
28        ids: List[int] | None = None,
29        name_contains: str | None = None,
30        name_exact: str | None = None,
31        page: int | None = None,
32        page_size: int | None = None,
33        ordering: str | None = None,
34        descending: bool = False,
35    ) -> PagedResult[Correspondent]:
36        """Return correspondents defined in paperless-ngx.
37
38        When ``page`` is ``None`` (the default), all pages are fetched
39        automatically and ``next`` / ``previous`` in the result are always
40        ``None``.  When ``page`` is set, only that page is fetched and
41        ``next`` / ``previous`` reflect the raw API values.
42
43        Args:
44            ids: Return only correspondents whose ID is in this list.
45            name_contains: Case-insensitive substring filter on name.
46            name_exact: Case-insensitive exact match on name.
47            page: Return only this specific page (1-based).
48            page_size: Number of results per page.
49            ordering: Field to sort by.
50            descending: When ``True``, reverses the sort direction.
51
52        Returns:
53            :class:`~easypaperless.models.paged_result.PagedResult` of
54            :class:`~easypaperless.models.correspondents.Correspondent` objects.
55        """
56        return cast(
57            PagedResult[Correspondent],
58            self._run(
59                self._async_correspondents.list(
60                    ids=ids,
61                    name_contains=name_contains,
62                    name_exact=name_exact,
63                    page=page,
64                    page_size=page_size,
65                    ordering=ordering,
66                    descending=descending,
67                )
68            ),
69        )

Return correspondents defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only correspondents whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.correspondents.Correspondent objects.

def get(self, id: int) -> easypaperless.Correspondent:
71    def get(self, id: int) -> Correspondent:
72        """Fetch a single correspondent by its ID.
73
74        Args:
75            id: Numeric correspondent ID.
76
77        Returns:
78            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
79
80        Raises:
81            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
82        """
83        return cast(Correspondent, self._run(self._async_correspondents.get(id)))

Fetch a single correspondent by its ID.

Arguments:
  • id: Numeric correspondent ID.
Returns:

The ~easypaperless.models.correspondents.Correspondent with the given ID.

Raises:
def create( self, *, name: str, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Correspondent:
 85    def create(
 86        self,
 87        *,
 88        name: str,
 89        match: str | Unset = UNSET,
 90        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 91        is_insensitive: bool = True,
 92        owner: int | None | Unset = UNSET,
 93        set_permissions: SetPermissions | None | Unset = UNSET,
 94    ) -> Correspondent:
 95        """Create a new correspondent.
 96
 97        Args:
 98            name: Correspondent name. Must be unique.
 99            match: Auto-matching pattern.
100            matching_algorithm: Controls how ``match`` is applied.
101                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
102                regular-expression matching.
103            is_insensitive: When ``True``, ``match`` is case-insensitive.
104                Defaults to ``True``, matching the paperless-ngx API default.
105            owner: Numeric user ID to assign as owner.
106            set_permissions: Explicit view/change permission sets.
107                Pass ``None`` to create with empty permissions.
108
109        Returns:
110            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
111        """
112        return cast(
113            Correspondent,
114            self._run(
115                self._async_correspondents.create(
116                    name=name,
117                    match=match,
118                    matching_algorithm=matching_algorithm,
119                    is_insensitive=is_insensitive,
120                    owner=owner,
121                    set_permissions=set_permissions,
122                )
123            ),
124        )

Create a new correspondent.

Arguments:
  • name: Correspondent name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.correspondents.Correspondent.

def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Correspondent:
126    def update(
127        self,
128        id: int,
129        *,
130        name: str | Unset = UNSET,
131        match: str | Unset = UNSET,
132        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
133        is_insensitive: bool | Unset = UNSET,
134        owner: int | None | Unset = UNSET,
135        set_permissions: SetPermissions | None | Unset = UNSET,
136    ) -> Correspondent:
137        """Partially update a correspondent (PATCH semantics).
138
139        Args:
140            id: Numeric ID of the correspondent to update.
141            name: Correspondent name.
142            match: Auto-matching pattern.
143            matching_algorithm: Controls how ``match`` is applied.
144                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
145                regular-expression matching.
146            is_insensitive: When ``True``, ``match`` is case-insensitive.
147            owner: Numeric user ID to assign as owner.
148                Pass ``None`` to clear the owner.
149                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
150            set_permissions: Explicit view/change permission sets.
151                Pass ``None`` to clear all permissions (overwrite with empty).
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153
154        Returns:
155            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
156        """
157        return cast(
158            Correspondent,
159            self._run(
160                self._async_correspondents.update(
161                    id,
162                    name=name,
163                    match=match,
164                    matching_algorithm=matching_algorithm,
165                    is_insensitive=is_insensitive,
166                    owner=owner,
167                    set_permissions=set_permissions,
168                )
169            ),
170        )

Partially update a correspondent (PATCH semantics).

Arguments:
  • id: Numeric ID of the correspondent to update.
  • name: Correspondent name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.correspondents.Correspondent.

def delete(self, id: int) -> None:
172    def delete(self, id: int) -> None:
173        """Delete a correspondent.
174
175        Args:
176            id: Numeric ID of the correspondent to delete.
177
178        Raises:
179            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
180        """
181        self._run(self._async_correspondents.delete(id))

Delete a correspondent.

Arguments:
  • id: Numeric ID of the correspondent to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
183    def bulk_delete(self, ids: List[int]) -> None:
184        """Permanently delete multiple correspondents in a single request.
185
186        Args:
187            ids: List of correspondent IDs to delete.
188        """
189        self._run(self._async_correspondents.bulk_delete(ids))

Permanently delete multiple correspondents in a single request.

Arguments:
  • ids: List of correspondent IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
191    def bulk_set_permissions(
192        self,
193        ids: List[int],
194        *,
195        set_permissions: SetPermissions | Unset = UNSET,
196        owner: int | None | Unset = UNSET,
197        merge: bool = False,
198    ) -> None:
199        """Set permissions and/or owner on multiple correspondents.
200
201        Args:
202            ids: List of correspondent IDs to modify.
203            set_permissions: Explicit view/change permission sets.
204                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
205            owner: Numeric user ID to assign as owner.
206                Pass ``None`` to clear the owner.
207                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
208            merge: When ``True``, new permissions are merged with existing ones.
209        """
210        self._run(
211            self._async_correspondents.bulk_set_permissions(
212                ids, set_permissions=set_permissions, owner=owner, merge=merge
213            )
214        )

Set permissions and/or owner on multiple correspondents.

Arguments:
  • ids: List of correspondent IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class SyncCustomFieldsResource:
 17class SyncCustomFieldsResource:
 18    """Sync accessor for custom fields: ``client.custom_fields``."""
 19
 20    def __init__(self, async_custom_fields: CustomFieldsResource, run: Any) -> None:
 21        self._async_custom_fields = async_custom_fields
 22        self._run = run
 23
 24    def list(
 25        self,
 26        *,
 27        name_contains: str | None = None,
 28        name_exact: str | None = None,
 29        page: int | None = None,
 30        page_size: int | None = None,
 31        ordering: str | None = None,
 32        descending: bool = False,
 33    ) -> PagedResult[CustomField]:
 34        """Return all custom fields defined in paperless-ngx.
 35
 36        When ``page`` is ``None`` (the default), all pages are fetched
 37        automatically and ``next`` / ``previous`` in the result are always
 38        ``None``.  When ``page`` is set, only that page is fetched and
 39        ``next`` / ``previous`` reflect the raw API values.
 40
 41        Args:
 42            name_contains: Case-insensitive substring filter on name.
 43            name_exact: Case-insensitive exact match on name.
 44            page: Return only this specific page (1-based).
 45            page_size: Number of results per page.
 46            ordering: Field to sort by.
 47            descending: When ``True``, reverses the sort direction.
 48
 49        Returns:
 50            :class:`~easypaperless.models.paged_result.PagedResult` of
 51            :class:`~easypaperless.models.custom_fields.CustomField` objects.
 52        """
 53        return cast(
 54            PagedResult[CustomField],
 55            self._run(
 56                self._async_custom_fields.list(
 57                    name_contains=name_contains,
 58                    name_exact=name_exact,
 59                    page=page,
 60                    page_size=page_size,
 61                    ordering=ordering,
 62                    descending=descending,
 63                )
 64            ),
 65        )
 66
 67    def get(self, id: int) -> CustomField:
 68        """Fetch a single custom field by its ID.
 69
 70        Args:
 71            id: Numeric custom-field ID.
 72
 73        Returns:
 74            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
 75
 76        Raises:
 77            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
 78        """
 79        return cast(CustomField, self._run(self._async_custom_fields.get(id)))
 80
 81    def create(
 82        self,
 83        *,
 84        name: str,
 85        data_type: str,
 86        extra_data: Any | None = None,
 87        owner: int | None | Unset = UNSET,
 88        set_permissions: SetPermissions | None | Unset = UNSET,
 89    ) -> CustomField:
 90        """Create a new custom field.
 91
 92        Args:
 93            name: Field name shown in the UI. Must be unique.
 94            data_type: Value type. One of ``"string"``, ``"boolean"``,
 95                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
 96                ``"url"``, ``"documentlink"``, ``"select"``.
 97            extra_data: Additional configuration for the field type.
 98            owner: Numeric user ID to assign as owner.
 99            set_permissions: Explicit view/change permission sets.
100                Pass ``None`` to create with empty permissions.
101
102        Returns:
103            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
104        """
105        return cast(
106            CustomField,
107            self._run(
108                self._async_custom_fields.create(
109                    name=name,
110                    data_type=data_type,
111                    extra_data=extra_data,
112                    owner=owner,
113                    set_permissions=set_permissions,
114                )
115            ),
116        )
117
118    def update(
119        self,
120        id: int,
121        *,
122        name: str | Unset = UNSET,
123        data_type: str | Unset = UNSET,
124        extra_data: Any | None | Unset = UNSET,
125        owner: int | None | Unset = UNSET,
126        set_permissions: SetPermissions | None | Unset = UNSET,
127    ) -> CustomField:
128        """Partially update a custom field (PATCH semantics).
129
130        Args:
131            id: Numeric ID of the custom field to update.
132            name: Field name shown in the UI.
133            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
134                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
135            extra_data: Additional configuration for the field type.
136            owner: Numeric user ID to assign as owner.
137                Pass ``None`` to clear the owner.
138                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
139            set_permissions: Explicit view/change permission sets.
140                Pass ``None`` to clear all permissions (overwrite with empty).
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142
143        Returns:
144            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
145        """
146        return cast(
147            CustomField,
148            self._run(
149                self._async_custom_fields.update(
150                    id,
151                    name=name,
152                    data_type=data_type,
153                    extra_data=extra_data,
154                    owner=owner,
155                    set_permissions=set_permissions,
156                )
157            ),
158        )
159
160    def delete(self, id: int) -> None:
161        """Delete a custom field.
162
163        Args:
164            id: Numeric ID of the custom field to delete.
165
166        Raises:
167            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
168        """
169        self._run(self._async_custom_fields.delete(id))

Sync accessor for custom fields: client.custom_fields.

SyncCustomFieldsResource( async_custom_fields: CustomFieldsResource, run: Any)
20    def __init__(self, async_custom_fields: CustomFieldsResource, run: Any) -> None:
21        self._async_custom_fields = async_custom_fields
22        self._run = run
def list( self, *, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[CustomField]:
24    def list(
25        self,
26        *,
27        name_contains: str | None = None,
28        name_exact: str | None = None,
29        page: int | None = None,
30        page_size: int | None = None,
31        ordering: str | None = None,
32        descending: bool = False,
33    ) -> PagedResult[CustomField]:
34        """Return all custom fields defined in paperless-ngx.
35
36        When ``page`` is ``None`` (the default), all pages are fetched
37        automatically and ``next`` / ``previous`` in the result are always
38        ``None``.  When ``page`` is set, only that page is fetched and
39        ``next`` / ``previous`` reflect the raw API values.
40
41        Args:
42            name_contains: Case-insensitive substring filter on name.
43            name_exact: Case-insensitive exact match on name.
44            page: Return only this specific page (1-based).
45            page_size: Number of results per page.
46            ordering: Field to sort by.
47            descending: When ``True``, reverses the sort direction.
48
49        Returns:
50            :class:`~easypaperless.models.paged_result.PagedResult` of
51            :class:`~easypaperless.models.custom_fields.CustomField` objects.
52        """
53        return cast(
54            PagedResult[CustomField],
55            self._run(
56                self._async_custom_fields.list(
57                    name_contains=name_contains,
58                    name_exact=name_exact,
59                    page=page,
60                    page_size=page_size,
61                    ordering=ordering,
62                    descending=descending,
63                )
64            ),
65        )

Return all custom fields defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.custom_fields.CustomField objects.

def get(self, id: int) -> easypaperless.CustomField:
67    def get(self, id: int) -> CustomField:
68        """Fetch a single custom field by its ID.
69
70        Args:
71            id: Numeric custom-field ID.
72
73        Returns:
74            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
75
76        Raises:
77            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
78        """
79        return cast(CustomField, self._run(self._async_custom_fields.get(id)))

Fetch a single custom field by its ID.

Arguments:
  • id: Numeric custom-field ID.
Returns:

The ~easypaperless.models.custom_fields.CustomField with the given ID.

Raises:
def create( self, *, name: str, data_type: str, extra_data: typing.Any | None = None, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.CustomField:
 81    def create(
 82        self,
 83        *,
 84        name: str,
 85        data_type: str,
 86        extra_data: Any | None = None,
 87        owner: int | None | Unset = UNSET,
 88        set_permissions: SetPermissions | None | Unset = UNSET,
 89    ) -> CustomField:
 90        """Create a new custom field.
 91
 92        Args:
 93            name: Field name shown in the UI. Must be unique.
 94            data_type: Value type. One of ``"string"``, ``"boolean"``,
 95                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
 96                ``"url"``, ``"documentlink"``, ``"select"``.
 97            extra_data: Additional configuration for the field type.
 98            owner: Numeric user ID to assign as owner.
 99            set_permissions: Explicit view/change permission sets.
100                Pass ``None`` to create with empty permissions.
101
102        Returns:
103            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
104        """
105        return cast(
106            CustomField,
107            self._run(
108                self._async_custom_fields.create(
109                    name=name,
110                    data_type=data_type,
111                    extra_data=extra_data,
112                    owner=owner,
113                    set_permissions=set_permissions,
114                )
115            ),
116        )

Create a new custom field.

Arguments:
  • name: Field name shown in the UI. Must be unique.
  • data_type: Value type. One of "string", "boolean", "integer", "float", "monetary", "date", "url", "documentlink", "select".
  • extra_data: Additional configuration for the field type.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.custom_fields.CustomField.

def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, data_type: str | easypaperless.Unset = UNSET, extra_data: typing.Any | None | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.CustomField:
118    def update(
119        self,
120        id: int,
121        *,
122        name: str | Unset = UNSET,
123        data_type: str | Unset = UNSET,
124        extra_data: Any | None | Unset = UNSET,
125        owner: int | None | Unset = UNSET,
126        set_permissions: SetPermissions | None | Unset = UNSET,
127    ) -> CustomField:
128        """Partially update a custom field (PATCH semantics).
129
130        Args:
131            id: Numeric ID of the custom field to update.
132            name: Field name shown in the UI.
133            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
134                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
135            extra_data: Additional configuration for the field type.
136            owner: Numeric user ID to assign as owner.
137                Pass ``None`` to clear the owner.
138                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
139            set_permissions: Explicit view/change permission sets.
140                Pass ``None`` to clear all permissions (overwrite with empty).
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142
143        Returns:
144            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
145        """
146        return cast(
147            CustomField,
148            self._run(
149                self._async_custom_fields.update(
150                    id,
151                    name=name,
152                    data_type=data_type,
153                    extra_data=extra_data,
154                    owner=owner,
155                    set_permissions=set_permissions,
156                )
157            ),
158        )

Partially update a custom field (PATCH semantics).

Arguments:
  • id: Numeric ID of the custom field to update.
  • name: Field name shown in the UI.
  • data_type: Value type (e.g. "string", "boolean", "integer"). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • extra_data: Additional configuration for the field type.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.custom_fields.CustomField.

def delete(self, id: int) -> None:
160    def delete(self, id: int) -> None:
161        """Delete a custom field.
162
163        Args:
164            id: Numeric ID of the custom field to delete.
165
166        Raises:
167            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
168        """
169        self._run(self._async_custom_fields.delete(id))

Delete a custom field.

Arguments:
  • id: Numeric ID of the custom field to delete.
Raises:
class SyncDocumentTypesResource:
 18class SyncDocumentTypesResource:
 19    """Sync accessor for document types: ``client.document_types``."""
 20
 21    def __init__(self, async_document_types: DocumentTypesResource, run: Any) -> None:
 22        self._async_document_types = async_document_types
 23        self._run = run
 24
 25    def list(
 26        self,
 27        *,
 28        ids: List[int] | None = None,
 29        name_contains: str | None = None,
 30        name_exact: str | None = None,
 31        page: int | None = None,
 32        page_size: int | None = None,
 33        ordering: str | None = None,
 34        descending: bool = False,
 35    ) -> PagedResult[DocumentType]:
 36        """Return document types defined in paperless-ngx.
 37
 38        When ``page`` is ``None`` (the default), all pages are fetched
 39        automatically and ``next`` / ``previous`` in the result are always
 40        ``None``.  When ``page`` is set, only that page is fetched and
 41        ``next`` / ``previous`` reflect the raw API values.
 42
 43        Args:
 44            ids: Return only document types whose ID is in this list.
 45            name_contains: Case-insensitive substring filter on name.
 46            name_exact: Case-insensitive exact match on name.
 47            page: Return only this specific page (1-based).
 48            page_size: Number of results per page.
 49            ordering: Field to sort by.
 50            descending: When ``True``, reverses the sort direction.
 51
 52        Returns:
 53            :class:`~easypaperless.models.paged_result.PagedResult` of
 54            :class:`~easypaperless.models.document_types.DocumentType` objects.
 55        """
 56        return cast(
 57            PagedResult[DocumentType],
 58            self._run(
 59                self._async_document_types.list(
 60                    ids=ids,
 61                    name_contains=name_contains,
 62                    name_exact=name_exact,
 63                    page=page,
 64                    page_size=page_size,
 65                    ordering=ordering,
 66                    descending=descending,
 67                )
 68            ),
 69        )
 70
 71    def get(self, id: int) -> DocumentType:
 72        """Fetch a single document type by its ID.
 73
 74        Args:
 75            id: Numeric document-type ID.
 76
 77        Returns:
 78            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
 79
 80        Raises:
 81            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
 82        """
 83        return cast(DocumentType, self._run(self._async_document_types.get(id)))
 84
 85    def create(
 86        self,
 87        *,
 88        name: str,
 89        match: str | Unset = UNSET,
 90        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 91        is_insensitive: bool = True,
 92        owner: int | None | Unset = UNSET,
 93        set_permissions: SetPermissions | None | Unset = UNSET,
 94    ) -> DocumentType:
 95        """Create a new document type.
 96
 97        Args:
 98            name: Document-type name. Must be unique.
 99            match: Auto-matching pattern.
100            matching_algorithm: Controls how ``match`` is applied.
101                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
102                regular-expression matching.
103            is_insensitive: When ``True``, ``match`` is case-insensitive.
104                Defaults to ``True``, matching the paperless-ngx API default.
105            owner: Numeric user ID to assign as owner.
106            set_permissions: Explicit view/change permission sets.
107                Pass ``None`` to create with empty permissions.
108
109        Returns:
110            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
111        """
112        return cast(
113            DocumentType,
114            self._run(
115                self._async_document_types.create(
116                    name=name,
117                    match=match,
118                    matching_algorithm=matching_algorithm,
119                    is_insensitive=is_insensitive,
120                    owner=owner,
121                    set_permissions=set_permissions,
122                )
123            ),
124        )
125
126    def update(
127        self,
128        id: int,
129        *,
130        name: str | Unset = UNSET,
131        match: str | Unset = UNSET,
132        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
133        is_insensitive: bool | Unset = UNSET,
134        owner: int | None | Unset = UNSET,
135        set_permissions: SetPermissions | None | Unset = UNSET,
136    ) -> DocumentType:
137        """Partially update a document type (PATCH semantics).
138
139        Args:
140            id: Numeric ID of the document type to update.
141            name: Document-type name.
142            match: Auto-matching pattern.
143            matching_algorithm: Controls how ``match`` is applied.
144                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
145                regular-expression matching.
146            is_insensitive: When ``True``, ``match`` is case-insensitive.
147            owner: Numeric user ID to assign as owner.
148                Pass ``None`` to clear the owner.
149                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
150            set_permissions: Explicit view/change permission sets.
151                Pass ``None`` to clear all permissions (overwrite with empty).
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153
154        Returns:
155            The updated :class:`~easypaperless.models.document_types.DocumentType`.
156        """
157        return cast(
158            DocumentType,
159            self._run(
160                self._async_document_types.update(
161                    id,
162                    name=name,
163                    match=match,
164                    matching_algorithm=matching_algorithm,
165                    is_insensitive=is_insensitive,
166                    owner=owner,
167                    set_permissions=set_permissions,
168                )
169            ),
170        )
171
172    def delete(self, id: int) -> None:
173        """Delete a document type.
174
175        Args:
176            id: Numeric ID of the document type to delete.
177
178        Raises:
179            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
180        """
181        self._run(self._async_document_types.delete(id))
182
183    def bulk_delete(self, ids: List[int]) -> None:
184        """Permanently delete multiple document types in a single request.
185
186        Args:
187            ids: List of document type IDs to delete.
188        """
189        self._run(self._async_document_types.bulk_delete(ids))
190
191    def bulk_set_permissions(
192        self,
193        ids: List[int],
194        *,
195        set_permissions: SetPermissions | Unset = UNSET,
196        owner: int | None | Unset = UNSET,
197        merge: bool = False,
198    ) -> None:
199        """Set permissions and/or owner on multiple document types.
200
201        Args:
202            ids: List of document type IDs to modify.
203            set_permissions: Explicit view/change permission sets.
204                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
205            owner: Numeric user ID to assign as owner.
206                Pass ``None`` to clear the owner.
207                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
208            merge: When ``True``, new permissions are merged with existing ones.
209        """
210        self._run(
211            self._async_document_types.bulk_set_permissions(
212                ids, set_permissions=set_permissions, owner=owner, merge=merge
213            )
214        )

Sync accessor for document types: client.document_types.

SyncDocumentTypesResource( async_document_types: DocumentTypesResource, run: Any)
21    def __init__(self, async_document_types: DocumentTypesResource, run: Any) -> None:
22        self._async_document_types = async_document_types
23        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[DocumentType]:
25    def list(
26        self,
27        *,
28        ids: List[int] | None = None,
29        name_contains: str | None = None,
30        name_exact: str | None = None,
31        page: int | None = None,
32        page_size: int | None = None,
33        ordering: str | None = None,
34        descending: bool = False,
35    ) -> PagedResult[DocumentType]:
36        """Return document types defined in paperless-ngx.
37
38        When ``page`` is ``None`` (the default), all pages are fetched
39        automatically and ``next`` / ``previous`` in the result are always
40        ``None``.  When ``page`` is set, only that page is fetched and
41        ``next`` / ``previous`` reflect the raw API values.
42
43        Args:
44            ids: Return only document types whose ID is in this list.
45            name_contains: Case-insensitive substring filter on name.
46            name_exact: Case-insensitive exact match on name.
47            page: Return only this specific page (1-based).
48            page_size: Number of results per page.
49            ordering: Field to sort by.
50            descending: When ``True``, reverses the sort direction.
51
52        Returns:
53            :class:`~easypaperless.models.paged_result.PagedResult` of
54            :class:`~easypaperless.models.document_types.DocumentType` objects.
55        """
56        return cast(
57            PagedResult[DocumentType],
58            self._run(
59                self._async_document_types.list(
60                    ids=ids,
61                    name_contains=name_contains,
62                    name_exact=name_exact,
63                    page=page,
64                    page_size=page_size,
65                    ordering=ordering,
66                    descending=descending,
67                )
68            ),
69        )

Return document types defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only document types whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.document_types.DocumentType objects.

def get(self, id: int) -> easypaperless.DocumentType:
71    def get(self, id: int) -> DocumentType:
72        """Fetch a single document type by its ID.
73
74        Args:
75            id: Numeric document-type ID.
76
77        Returns:
78            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
79
80        Raises:
81            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
82        """
83        return cast(DocumentType, self._run(self._async_document_types.get(id)))

Fetch a single document type by its ID.

Arguments:
  • id: Numeric document-type ID.
Returns:

The ~easypaperless.models.document_types.DocumentType with the given ID.

Raises:
def create( self, *, name: str, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.DocumentType:
 85    def create(
 86        self,
 87        *,
 88        name: str,
 89        match: str | Unset = UNSET,
 90        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 91        is_insensitive: bool = True,
 92        owner: int | None | Unset = UNSET,
 93        set_permissions: SetPermissions | None | Unset = UNSET,
 94    ) -> DocumentType:
 95        """Create a new document type.
 96
 97        Args:
 98            name: Document-type name. Must be unique.
 99            match: Auto-matching pattern.
100            matching_algorithm: Controls how ``match`` is applied.
101                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
102                regular-expression matching.
103            is_insensitive: When ``True``, ``match`` is case-insensitive.
104                Defaults to ``True``, matching the paperless-ngx API default.
105            owner: Numeric user ID to assign as owner.
106            set_permissions: Explicit view/change permission sets.
107                Pass ``None`` to create with empty permissions.
108
109        Returns:
110            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
111        """
112        return cast(
113            DocumentType,
114            self._run(
115                self._async_document_types.create(
116                    name=name,
117                    match=match,
118                    matching_algorithm=matching_algorithm,
119                    is_insensitive=is_insensitive,
120                    owner=owner,
121                    set_permissions=set_permissions,
122                )
123            ),
124        )

Create a new document type.

Arguments:
  • name: Document-type name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.document_types.DocumentType.

def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.DocumentType:
126    def update(
127        self,
128        id: int,
129        *,
130        name: str | Unset = UNSET,
131        match: str | Unset = UNSET,
132        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
133        is_insensitive: bool | Unset = UNSET,
134        owner: int | None | Unset = UNSET,
135        set_permissions: SetPermissions | None | Unset = UNSET,
136    ) -> DocumentType:
137        """Partially update a document type (PATCH semantics).
138
139        Args:
140            id: Numeric ID of the document type to update.
141            name: Document-type name.
142            match: Auto-matching pattern.
143            matching_algorithm: Controls how ``match`` is applied.
144                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
145                regular-expression matching.
146            is_insensitive: When ``True``, ``match`` is case-insensitive.
147            owner: Numeric user ID to assign as owner.
148                Pass ``None`` to clear the owner.
149                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
150            set_permissions: Explicit view/change permission sets.
151                Pass ``None`` to clear all permissions (overwrite with empty).
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153
154        Returns:
155            The updated :class:`~easypaperless.models.document_types.DocumentType`.
156        """
157        return cast(
158            DocumentType,
159            self._run(
160                self._async_document_types.update(
161                    id,
162                    name=name,
163                    match=match,
164                    matching_algorithm=matching_algorithm,
165                    is_insensitive=is_insensitive,
166                    owner=owner,
167                    set_permissions=set_permissions,
168                )
169            ),
170        )

Partially update a document type (PATCH semantics).

Arguments:
  • id: Numeric ID of the document type to update.
  • name: Document-type name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.document_types.DocumentType.

def delete(self, id: int) -> None:
172    def delete(self, id: int) -> None:
173        """Delete a document type.
174
175        Args:
176            id: Numeric ID of the document type to delete.
177
178        Raises:
179            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
180        """
181        self._run(self._async_document_types.delete(id))

Delete a document type.

Arguments:
  • id: Numeric ID of the document type to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
183    def bulk_delete(self, ids: List[int]) -> None:
184        """Permanently delete multiple document types in a single request.
185
186        Args:
187            ids: List of document type IDs to delete.
188        """
189        self._run(self._async_document_types.bulk_delete(ids))

Permanently delete multiple document types in a single request.

Arguments:
  • ids: List of document type IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
191    def bulk_set_permissions(
192        self,
193        ids: List[int],
194        *,
195        set_permissions: SetPermissions | Unset = UNSET,
196        owner: int | None | Unset = UNSET,
197        merge: bool = False,
198    ) -> None:
199        """Set permissions and/or owner on multiple document types.
200
201        Args:
202            ids: List of document type IDs to modify.
203            set_permissions: Explicit view/change permission sets.
204                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
205            owner: Numeric user ID to assign as owner.
206                Pass ``None`` to clear the owner.
207                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
208            merge: When ``True``, new permissions are merged with existing ones.
209        """
210        self._run(
211            self._async_document_types.bulk_set_permissions(
212                ids, set_permissions=set_permissions, owner=owner, merge=merge
213            )
214        )

Set permissions and/or owner on multiple document types.

Arguments:
  • ids: List of document type IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class SyncDocumentsResource:
 91class SyncDocumentsResource:
 92    """Sync accessor for documents: ``client.documents``."""
 93
 94    def __init__(self, async_documents: DocumentsResource, run: Any) -> None:
 95        self._async_documents = async_documents
 96        self._run = run
 97        self.notes = SyncNotesResource(async_documents.notes, run)
 98
 99    def history(
100        self,
101        document_id: int,
102        *,
103        page: int | None = None,
104        page_size: int | None = None,
105    ) -> PagedResult[AuditLogEntry]:
106        """Fetch the audit log for a document.
107
108        The paperless-ngx ``/api/documents/{id}/history/`` endpoint returns a
109        plain JSON array rather than a paginated envelope.  This method wraps
110        the response into a :class:`~easypaperless.models.paged_result.PagedResult`
111        so callers always receive a consistent return type.
112
113        Args:
114            document_id: Numeric ID of the document whose history to retrieve.
115            page: Forwarded to the API as a query parameter when provided.
116                Effect depends on the paperless-ngx version; the server may
117                ignore this parameter.
118            page_size: Forwarded to the API as a query parameter when provided.
119
120        Returns:
121            :class:`~easypaperless.models.paged_result.PagedResult` of
122            :class:`~easypaperless.models.documents.AuditLogEntry` objects,
123            ordered by timestamp descending.
124
125        Raises:
126            ~easypaperless.exceptions.NotFoundError: If no document exists
127                with that ID.
128        """
129        return cast(
130            PagedResult[AuditLogEntry],
131            self._run(self._async_documents.history(document_id, page=page, page_size=page_size)),
132        )
133
134    def get(self, id: int, *, include_metadata: bool = False) -> Document:
135        """Fetch a single document by its ID.
136
137        Args:
138            id: Numeric paperless-ngx document ID.
139            include_metadata: When ``True``, the extended file-level metadata
140                is fetched concurrently and attached to the document.
141                Default: ``False``.
142
143        Returns:
144            The :class:`~easypaperless.models.documents.Document` with the
145            given ID.
146
147        Raises:
148            ~easypaperless.exceptions.NotFoundError: If no document exists
149                with that ID.
150        """
151        return cast(
152            Document, self._run(self._async_documents.get(id, include_metadata=include_metadata))
153        )
154
155    def get_metadata(self, id: int) -> DocumentMetadata:
156        """Fetch the extended file-level metadata for a document.
157
158        Args:
159            id: Numeric paperless-ngx document ID.
160
161        Returns:
162            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
163
164        Raises:
165            ~easypaperless.exceptions.NotFoundError: If no document exists
166                with that ID.
167        """
168        return cast(DocumentMetadata, self._run(self._async_documents.get_metadata(id)))
169
170    def list(
171        self,
172        *,
173        search: str | None = None,
174        search_mode: str = "title_or_content",
175        ids: List[int] | None = None,
176        tags: List[int | str] | None = None,
177        any_tags: List[int | str] | None = None,
178        exclude_tags: List[int | str] | None = None,
179        correspondent: int | str | None | Unset = UNSET,
180        any_correspondent: List[int | str] | None = None,
181        exclude_correspondents: List[int | str] | None = None,
182        document_type: int | str | None | Unset = UNSET,
183        document_type_name_contains: str | None = None,
184        document_type_name_exact: str | None = None,
185        any_document_type: List[int | str] | None = None,
186        exclude_document_types: List[int | str] | None = None,
187        storage_path: int | str | None | Unset = UNSET,
188        any_storage_paths: List[int | str] | None = None,
189        exclude_storage_paths: List[int | str] | None = None,
190        owner: int | None | Unset = UNSET,
191        exclude_owners: List[int] | None = None,
192        custom_fields: List[int | str] | None = None,
193        any_custom_fields: List[int | str] | None = None,
194        exclude_custom_fields: List[int | str] | None = None,
195        custom_field_query: List[Any] | None = None,
196        archive_serial_number: int | None | Unset = UNSET,
197        archive_serial_number_from: int | None = None,
198        archive_serial_number_till: int | None = None,
199        created_after: date | str | None = None,
200        created_before: date | str | None = None,
201        added_after: date | datetime | str | None = None,
202        added_from: date | datetime | str | None = None,
203        added_before: date | datetime | str | None = None,
204        added_until: date | datetime | str | None = None,
205        modified_after: date | datetime | str | None = None,
206        modified_from: date | datetime | str | None = None,
207        modified_before: date | datetime | str | None = None,
208        modified_until: date | datetime | str | None = None,
209        checksum: str | None = None,
210        page_size: int = 25,
211        page: int | None = None,
212        ordering: str | None = None,
213        descending: bool = False,
214        max_results: int | None = None,
215        on_page: Callable[[int, int | None], None] | None = None,
216    ) -> PagedResult[Document]:
217        """Return a filtered list of documents.
218
219        All tag, correspondent, document-type, storage-path, and custom-field
220        parameters accept either integer IDs or string names.
221
222        When ``page`` is ``None`` (the default), all pages are fetched
223        automatically and ``next`` / ``previous`` in the returned
224        :class:`~easypaperless.models.paged_result.PagedResult` are always
225        ``None`` — even if ``max_results`` truncates the final result set.
226        ``count`` always reflects the server total, not the truncated length.
227        When ``page`` is set to a specific integer, only that one page is
228        fetched and ``next`` / ``previous`` contain the raw API values.
229
230        Args:
231            search: Search string.  Behaviour depends on ``search_mode``.
232            search_mode: How ``search`` is applied.  One of:
233                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
234                ``"original_filename"``.
235            ids: Return only documents whose ID is in this list.
236            tags: Documents must have **all** of these tags (AND semantics).
237            any_tags: Documents must have **at least one** of these tags.
238            exclude_tags: Documents must have **none** of these tags.
239            correspondent: Filter to documents assigned to this correspondent.
240                Pass ``None`` to return only documents with no correspondent set.
241            any_correspondent: Filter to documents assigned to any of these.
242            exclude_correspondents: Exclude documents assigned to any of these.
243            document_type: Filter to documents of exactly this type.
244                Pass ``None`` to return only documents with no document type set.
245            document_type_name_contains: Case-insensitive substring filter on document type name.
246            document_type_name_exact: Case-insensitive exact match on document type name.
247            any_document_type: Filter to documents whose type is any of these.
248            exclude_document_types: Exclude documents whose type is any of these.
249            storage_path: Filter to documents assigned to this storage path.
250                Pass ``None`` to return only documents with no storage path set.
251            any_storage_paths: Filter to documents assigned to any of these paths.
252            exclude_storage_paths: Exclude documents assigned to any of these paths.
253            owner: Filter to documents owned by this user ID.
254                Pass ``None`` to return only documents with no owner set.
255            exclude_owners: Exclude documents owned by any of these user IDs.
256            custom_fields: Documents must have **all** of these custom fields set.
257            any_custom_fields: Documents must have **at least one** of these fields.
258            exclude_custom_fields: Documents must have **none** of these fields.
259            custom_field_query: Filter documents by custom field values using a nested
260                query structure. See the `paperless-ngx API docs
261                <https://docs.paperless-ngx.com/api/#filtering-by-custom-fields>`_ for
262                the query format.
263            archive_serial_number: Filter by exact archive serial number.
264                Pass ``None`` to return only documents with no ASN set.
265            archive_serial_number_from: Filter by ASN >= this value.
266            archive_serial_number_till: Filter by ASN <= this value.
267            created_after: Only documents created after this date.
268                String input must be ISO-8601: ``"YYYY-MM-DD"``.
269            created_before: Only documents created before this date.
270                String input must be ISO-8601: ``"YYYY-MM-DD"``.
271            added_after: Only documents added after this date/time.
272                String input must be ISO-8601: ``"YYYY-MM-DD"`` for date precision or
273                ``"YYYY-MM-DDTHH:MM:SS"`` for datetime precision.
274            added_from: Only documents added on or after this date/time.
275                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
276            added_before: Only documents added before this date/time.
277                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
278            added_until: Only documents added on or before this date/time.
279                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
280            modified_after: Only documents modified after this date/time.
281                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
282            modified_from: Only documents modified on or after this date/time.
283                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
284            modified_before: Only documents modified before this date/time.
285                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
286            modified_until: Only documents modified on or before this date/time.
287                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
288            checksum: MD5 checksum of the original file (exact match).
289            page_size: Number of results per API page.  Default: ``25``.
290            page: Return only this specific page (1-based).
291            ordering: Field name to sort by.
292            descending: When ``True``, reverses the sort direction.
293            max_results: Stop after collecting this many documents.
294            on_page: Callback invoked after each page fetch.
295
296        Returns:
297            :class:`~easypaperless.models.paged_result.PagedResult` of
298            :class:`~easypaperless.models.documents.Document` objects.
299        """
300        return cast(
301            PagedResult[Document],
302            self._run(
303                self._async_documents.list(
304                    search=search,
305                    search_mode=search_mode,
306                    ids=ids,
307                    tags=tags,
308                    any_tags=any_tags,
309                    exclude_tags=exclude_tags,
310                    correspondent=correspondent,
311                    any_correspondent=any_correspondent,
312                    exclude_correspondents=exclude_correspondents,
313                    document_type=document_type,
314                    document_type_name_contains=document_type_name_contains,
315                    document_type_name_exact=document_type_name_exact,
316                    any_document_type=any_document_type,
317                    exclude_document_types=exclude_document_types,
318                    storage_path=storage_path,
319                    any_storage_paths=any_storage_paths,
320                    exclude_storage_paths=exclude_storage_paths,
321                    owner=owner,
322                    exclude_owners=exclude_owners,
323                    custom_fields=custom_fields,
324                    any_custom_fields=any_custom_fields,
325                    exclude_custom_fields=exclude_custom_fields,
326                    custom_field_query=custom_field_query,
327                    archive_serial_number=archive_serial_number,
328                    archive_serial_number_from=archive_serial_number_from,
329                    archive_serial_number_till=archive_serial_number_till,
330                    created_after=created_after,
331                    created_before=created_before,
332                    added_after=added_after,
333                    added_from=added_from,
334                    added_before=added_before,
335                    added_until=added_until,
336                    modified_after=modified_after,
337                    modified_from=modified_from,
338                    modified_before=modified_before,
339                    modified_until=modified_until,
340                    checksum=checksum,
341                    page_size=page_size,
342                    page=page,
343                    ordering=ordering,
344                    descending=descending,
345                    max_results=max_results,
346                    on_page=on_page,
347                )
348            ),
349        )
350
351    def update(
352        self,
353        id: int,
354        *,
355        title: str | Unset = UNSET,
356        content: str | Unset = UNSET,
357        created: date | str | None | Unset = UNSET,
358        correspondent: int | str | None | Unset = UNSET,
359        document_type: int | str | None | Unset = UNSET,
360        storage_path: int | str | None | Unset = UNSET,
361        tags: List[int | str] | None | Unset = UNSET,
362        archive_serial_number: int | None | Unset = UNSET,
363        custom_fields: List[dict[str, Any]] | None | Unset = UNSET,
364        owner: int | None | Unset = UNSET,
365        set_permissions: SetPermissions | None | Unset = UNSET,
366        remove_inbox_tags: bool | None | Unset = UNSET,
367    ) -> Document:
368        """Partially update a document (PATCH semantics).
369
370        Args:
371            id: Numeric ID of the document to update.
372            title: New document title.
373            content: OCR text content of the document.
374            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
375                :class:`~datetime.date` object.
376            correspondent: Correspondent to assign, as an ID or name.
377                Pass ``None`` to clear the correspondent.
378            document_type: Document type to assign, as an ID or name.
379                Pass ``None`` to clear the document type.
380            storage_path: Storage path to assign, as an ID or name.
381                Pass ``None`` to clear the storage path.
382            tags: Full replacement list of tags (IDs or names).
383            archive_serial_number: Archive serial number to assign.
384                Pass ``None`` to clear the archive serial number.
385            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
386            owner: Numeric user ID to assign as document owner.
387                Pass ``None`` to clear the owner.
388            set_permissions: Explicit view/change permission sets.
389                Pass ``None`` to clear all permissions (overwrite with empty).
390                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
391            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
392
393        Returns:
394            The updated :class:`~easypaperless.models.documents.Document`.
395        """
396        return cast(
397            Document,
398            self._run(
399                self._async_documents.update(
400                    id,
401                    title=title,
402                    content=content,
403                    created=created,
404                    correspondent=correspondent,
405                    document_type=document_type,
406                    storage_path=storage_path,
407                    tags=tags,
408                    archive_serial_number=archive_serial_number,
409                    custom_fields=custom_fields,
410                    owner=owner,
411                    set_permissions=set_permissions,
412                    remove_inbox_tags=remove_inbox_tags,
413                )
414            ),
415        )
416
417    def delete(self, id: int) -> None:
418        """Permanently delete a document.
419
420        Args:
421            id: Numeric ID of the document to delete.
422
423        Raises:
424            ~easypaperless.exceptions.NotFoundError: If no document exists
425                with that ID.
426        """
427        self._run(self._async_documents.delete(id))
428
429    def download(self, id: int, *, original: bool = False) -> bytes:
430        """Download the binary content of a document.
431
432        Args:
433            id: Numeric ID of the document to download.
434            original: If ``False`` *(default)*, returns the archived PDF
435                (``GET /documents/{id}/download/``).
436                If ``True``, returns the original uploaded file
437                (``GET /documents/{id}/download/?original=true``).
438
439        Returns:
440            Raw file bytes.
441        """
442        return cast(bytes, self._run(self._async_documents.download(id, original=original)))
443
444    def thumbnail(self, id: int) -> bytes:
445        """Fetch the thumbnail image of a document.
446
447        Args:
448            id: Numeric ID of the document whose thumbnail to retrieve.
449
450        Returns:
451            Raw binary content of the thumbnail image.
452
453        Raises:
454            ~easypaperless.exceptions.NotFoundError: If no document exists
455                with that ID.
456            ~easypaperless.exceptions.ServerError: If the server returns an
457                HTML page (e.g. an auth redirect) instead of the image.
458        """
459        return cast(bytes, self._run(self._async_documents.thumbnail(id)))
460
461    def upload(
462        self,
463        file: str | Path,
464        *,
465        title: str | Unset = UNSET,
466        created: date | str | None = None,
467        correspondent: int | str | None | Unset = UNSET,
468        document_type: int | str | None | Unset = UNSET,
469        storage_path: int | str | None | Unset = UNSET,
470        tags: List[int | str] | None = None,
471        archive_serial_number: int | None | Unset = UNSET,
472        custom_fields: List[dict[str, Any]] | None = None,
473        wait: bool = False,
474        poll_interval: float | None = None,
475        poll_timeout: float | None = None,
476    ) -> str | Document:
477        """Upload a document to paperless-ngx.
478
479        Args:
480            file: Path to the file to upload.
481            title: Title to assign to the document.
482            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
483                :class:`~datetime.date` object.
484            correspondent: Correspondent to assign, as an ID or name.
485            document_type: Document type to assign, as an ID or name.
486            storage_path: Storage path to assign, as an ID or name.
487            tags: Tags to assign, as IDs or names.
488            archive_serial_number: Archive serial number to assign.
489            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
490            wait: If ``False`` *(default)*, returns immediately with the task ID.
491                If ``True``, polls until processing completes.
492            poll_interval: Seconds between task-status checks while waiting for
493                processing to complete (requires ``wait=True``). Overrides the
494                client-level default. When omitted, falls back to the client-level
495                ``poll_interval`` (``2.0`` s unless changed at construction).
496            poll_timeout: Maximum seconds to wait before raising
497                :exc:`~easypaperless.exceptions.TaskTimeoutError` (requires
498                ``wait=True``). Overrides the client-level default. When omitted,
499                falls back to the client-level ``poll_timeout`` (``60.0`` s unless
500                changed at construction).
501
502        Returns:
503            The Celery task ID string when ``wait=False``, or the fully
504            processed :class:`~easypaperless.models.documents.Document`
505            when ``wait=True``.
506
507        Raises:
508            ~easypaperless.exceptions.UploadError: If processing fails.
509            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
510        """
511        return cast(
512            str | Document,
513            self._run(
514                self._async_documents.upload(
515                    file,
516                    title=title,
517                    created=created,
518                    correspondent=correspondent,
519                    document_type=document_type,
520                    storage_path=storage_path,
521                    tags=tags,
522                    archive_serial_number=archive_serial_number,
523                    custom_fields=custom_fields,
524                    wait=wait,
525                    poll_interval=poll_interval,
526                    poll_timeout=poll_timeout,
527                )
528            ),
529        )
530
531    def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
532        """Add a tag to multiple documents in a single request.
533
534        Args:
535            document_ids: List of document IDs to tag.
536            tag: Tag to add, as an ID or name.
537        """
538        self._run(self._async_documents.bulk_add_tag(document_ids, tag))
539
540    def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
541        """Remove a tag from multiple documents in a single request.
542
543        Args:
544            document_ids: List of document IDs to un-tag.
545            tag: Tag to remove, as an ID or name.
546        """
547        self._run(self._async_documents.bulk_remove_tag(document_ids, tag))
548
549    def bulk_modify_tags(
550        self,
551        document_ids: List[int],
552        *,
553        add_tags: List[int | str] | None = None,
554        remove_tags: List[int | str] | None = None,
555    ) -> None:
556        """Add and/or remove tags on multiple documents atomically.
557
558        Args:
559            document_ids: List of document IDs to modify.
560            add_tags: Tags to add, as IDs or names.
561            remove_tags: Tags to remove, as IDs or names.
562        """
563        self._run(
564            self._async_documents.bulk_modify_tags(
565                document_ids, add_tags=add_tags, remove_tags=remove_tags
566            )
567        )
568
569    def bulk_delete(self, document_ids: List[int]) -> None:
570        """Permanently delete multiple documents in a single request.
571
572        Args:
573            document_ids: List of document IDs to delete.
574        """
575        self._run(self._async_documents.bulk_delete(document_ids))
576
577    def bulk_set_correspondent(
578        self, document_ids: List[int], correspondent: int | str | None
579    ) -> None:
580        """Assign a correspondent to multiple documents in a single request.
581
582        Args:
583            document_ids: List of document IDs to modify.
584            correspondent: Correspondent to assign, as an ID or name.
585                Pass ``None`` to clear.
586        """
587        self._run(self._async_documents.bulk_set_correspondent(document_ids, correspondent))
588
589    def bulk_set_document_type(
590        self, document_ids: List[int], document_type: int | str | None
591    ) -> None:
592        """Assign a document type to multiple documents in a single request.
593
594        Args:
595            document_ids: List of document IDs to modify.
596            document_type: Document type to assign, as an ID or name.
597                Pass ``None`` to clear.
598        """
599        self._run(self._async_documents.bulk_set_document_type(document_ids, document_type))
600
601    def bulk_set_storage_path(
602        self, document_ids: List[int], storage_path: int | str | None
603    ) -> None:
604        """Assign a storage path to multiple documents in a single request.
605
606        Args:
607            document_ids: List of document IDs to modify.
608            storage_path: Storage path to assign, as an ID or name.
609                Pass ``None`` to clear.
610        """
611        self._run(self._async_documents.bulk_set_storage_path(document_ids, storage_path))
612
613    def bulk_modify_custom_fields(
614        self,
615        document_ids: List[int],
616        *,
617        add_fields: List[dict[str, Any]] | None = None,
618        remove_fields: List[int] | None = None,
619    ) -> None:
620        """Add and/or remove custom field values on multiple documents.
621
622        Args:
623            document_ids: List of document IDs to modify.
624            add_fields: Custom-field value dicts to add.
625            remove_fields: Custom-field IDs whose values should be removed.
626        """
627        self._run(
628            self._async_documents.bulk_modify_custom_fields(
629                document_ids, add_fields=add_fields, remove_fields=remove_fields
630            )
631        )
632
633    def bulk_set_permissions(
634        self,
635        document_ids: List[int],
636        *,
637        set_permissions: SetPermissions | Unset = UNSET,
638        owner: int | None | Unset = UNSET,
639        merge: bool = False,
640    ) -> None:
641        """Set permissions and/or owner on multiple documents.
642
643        Args:
644            document_ids: List of document IDs to modify.
645            set_permissions: Explicit view/change permission sets.
646                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
647            owner: Numeric user ID to assign as document owner.
648                Pass ``None`` to clear the owner.
649                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
650            merge: When ``True``, new permissions are merged with existing ones.
651        """
652        self._run(
653            self._async_documents.bulk_set_permissions(
654                document_ids,
655                set_permissions=set_permissions,
656                owner=owner,
657                merge=merge,
658            )
659        )
660
661    def bulk_download(
662        self,
663        document_ids: List[int],
664        *,
665        content: Literal["archive", "originals", "both"] = "archive",
666        compression: Literal["none", "deflated", "bzip2", "lzma"] = "none",
667        follow_formatting: bool = False,
668    ) -> bytes:
669        """Download multiple documents as a single ZIP archive.
670
671        Args:
672            document_ids: List of document IDs to include in the ZIP.
673            content: File variant to include.  One of ``"archive"`` *(default)*,
674                ``"originals"``, or ``"both"``.
675            compression: ZIP compression algorithm.  One of ``"none"`` *(default)*,
676                ``"deflated"``, ``"bzip2"``, or ``"lzma"``.
677            follow_formatting: When ``True``, filenames inside the ZIP follow
678                the storage path formatting configured in paperless-ngx.
679                Default: ``False``.
680
681        Returns:
682            Raw bytes of the ZIP archive.
683        """
684        return cast(
685            bytes,
686            self._run(
687                self._async_documents.bulk_download(
688                    document_ids,
689                    content=content,
690                    compression=compression,
691                    follow_formatting=follow_formatting,
692                )
693            ),
694        )

Sync accessor for documents: client.documents.

SyncDocumentsResource( async_documents: DocumentsResource, run: Any)
94    def __init__(self, async_documents: DocumentsResource, run: Any) -> None:
95        self._async_documents = async_documents
96        self._run = run
97        self.notes = SyncNotesResource(async_documents.notes, run)
notes
def history( self, document_id: int, *, page: int | None = None, page_size: int | None = None) -> easypaperless.PagedResult[AuditLogEntry]:
 99    def history(
100        self,
101        document_id: int,
102        *,
103        page: int | None = None,
104        page_size: int | None = None,
105    ) -> PagedResult[AuditLogEntry]:
106        """Fetch the audit log for a document.
107
108        The paperless-ngx ``/api/documents/{id}/history/`` endpoint returns a
109        plain JSON array rather than a paginated envelope.  This method wraps
110        the response into a :class:`~easypaperless.models.paged_result.PagedResult`
111        so callers always receive a consistent return type.
112
113        Args:
114            document_id: Numeric ID of the document whose history to retrieve.
115            page: Forwarded to the API as a query parameter when provided.
116                Effect depends on the paperless-ngx version; the server may
117                ignore this parameter.
118            page_size: Forwarded to the API as a query parameter when provided.
119
120        Returns:
121            :class:`~easypaperless.models.paged_result.PagedResult` of
122            :class:`~easypaperless.models.documents.AuditLogEntry` objects,
123            ordered by timestamp descending.
124
125        Raises:
126            ~easypaperless.exceptions.NotFoundError: If no document exists
127                with that ID.
128        """
129        return cast(
130            PagedResult[AuditLogEntry],
131            self._run(self._async_documents.history(document_id, page=page, page_size=page_size)),
132        )

Fetch the audit log for a document.

The paperless-ngx /api/documents/{id}/history/ endpoint returns a plain JSON array rather than a paginated envelope. This method wraps the response into a ~easypaperless.models.paged_result.PagedResult so callers always receive a consistent return type.

Arguments:
  • document_id: Numeric ID of the document whose history to retrieve.
  • page: Forwarded to the API as a query parameter when provided. Effect depends on the paperless-ngx version; the server may ignore this parameter.
  • page_size: Forwarded to the API as a query parameter when provided.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.AuditLogEntry objects, ordered by timestamp descending.

Raises:
def get( self, id: int, *, include_metadata: bool = False) -> easypaperless.Document:
134    def get(self, id: int, *, include_metadata: bool = False) -> Document:
135        """Fetch a single document by its ID.
136
137        Args:
138            id: Numeric paperless-ngx document ID.
139            include_metadata: When ``True``, the extended file-level metadata
140                is fetched concurrently and attached to the document.
141                Default: ``False``.
142
143        Returns:
144            The :class:`~easypaperless.models.documents.Document` with the
145            given ID.
146
147        Raises:
148            ~easypaperless.exceptions.NotFoundError: If no document exists
149                with that ID.
150        """
151        return cast(
152            Document, self._run(self._async_documents.get(id, include_metadata=include_metadata))
153        )

Fetch a single document by its ID.

Arguments:
  • id: Numeric paperless-ngx document ID.
  • include_metadata: When True, the extended file-level metadata is fetched concurrently and attached to the document. Default: False.
Returns:

The ~easypaperless.models.documents.Document with the given ID.

Raises:
def get_metadata(self, id: int) -> easypaperless.DocumentMetadata:
155    def get_metadata(self, id: int) -> DocumentMetadata:
156        """Fetch the extended file-level metadata for a document.
157
158        Args:
159            id: Numeric paperless-ngx document ID.
160
161        Returns:
162            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
163
164        Raises:
165            ~easypaperless.exceptions.NotFoundError: If no document exists
166                with that ID.
167        """
168        return cast(DocumentMetadata, self._run(self._async_documents.get_metadata(id)))

Fetch the extended file-level metadata for a document.

Arguments:
  • id: Numeric paperless-ngx document ID.
Returns:

A ~easypaperless.models.documents.DocumentMetadata instance.

Raises:
def list( self, *, search: str | None = None, search_mode: str = 'title_or_content', ids: Optional[List[int]] = None, tags: Optional[List[Union[str, int]]] = None, any_tags: Optional[List[Union[str, int]]] = None, exclude_tags: Optional[List[Union[str, int]]] = None, correspondent: int | str | None | easypaperless.Unset = UNSET, any_correspondent: Optional[List[Union[str, int]]] = None, exclude_correspondents: Optional[List[Union[str, int]]] = None, document_type: int | str | None | easypaperless.Unset = UNSET, document_type_name_contains: str | None = None, document_type_name_exact: str | None = None, any_document_type: Optional[List[Union[str, int]]] = None, exclude_document_types: Optional[List[Union[str, int]]] = None, storage_path: int | str | None | easypaperless.Unset = UNSET, any_storage_paths: Optional[List[Union[str, int]]] = None, exclude_storage_paths: Optional[List[Union[str, int]]] = None, owner: int | None | easypaperless.Unset = UNSET, exclude_owners: Optional[List[int]] = None, custom_fields: Optional[List[Union[str, int]]] = None, any_custom_fields: Optional[List[Union[str, int]]] = None, exclude_custom_fields: Optional[List[Union[str, int]]] = None, custom_field_query: Optional[List[Any]] = None, archive_serial_number: int | None | easypaperless.Unset = UNSET, archive_serial_number_from: int | None = None, archive_serial_number_till: int | None = None, created_after: datetime.date | str | None = None, created_before: datetime.date | str | None = None, added_after: datetime.date | datetime.datetime | str | None = None, added_from: datetime.date | datetime.datetime | str | None = None, added_before: datetime.date | datetime.datetime | str | None = None, added_until: datetime.date | datetime.datetime | str | None = None, modified_after: datetime.date | datetime.datetime | str | None = None, modified_from: datetime.date | datetime.datetime | str | None = None, modified_before: datetime.date | datetime.datetime | str | None = None, modified_until: datetime.date | datetime.datetime | str | None = None, checksum: str | None = None, page_size: int = 25, page: int | None = None, ordering: str | None = None, descending: bool = False, max_results: int | None = None, on_page: Callable[[int, int | None], None] | None = None) -> easypaperless.PagedResult[Document]:
170    def list(
171        self,
172        *,
173        search: str | None = None,
174        search_mode: str = "title_or_content",
175        ids: List[int] | None = None,
176        tags: List[int | str] | None = None,
177        any_tags: List[int | str] | None = None,
178        exclude_tags: List[int | str] | None = None,
179        correspondent: int | str | None | Unset = UNSET,
180        any_correspondent: List[int | str] | None = None,
181        exclude_correspondents: List[int | str] | None = None,
182        document_type: int | str | None | Unset = UNSET,
183        document_type_name_contains: str | None = None,
184        document_type_name_exact: str | None = None,
185        any_document_type: List[int | str] | None = None,
186        exclude_document_types: List[int | str] | None = None,
187        storage_path: int | str | None | Unset = UNSET,
188        any_storage_paths: List[int | str] | None = None,
189        exclude_storage_paths: List[int | str] | None = None,
190        owner: int | None | Unset = UNSET,
191        exclude_owners: List[int] | None = None,
192        custom_fields: List[int | str] | None = None,
193        any_custom_fields: List[int | str] | None = None,
194        exclude_custom_fields: List[int | str] | None = None,
195        custom_field_query: List[Any] | None = None,
196        archive_serial_number: int | None | Unset = UNSET,
197        archive_serial_number_from: int | None = None,
198        archive_serial_number_till: int | None = None,
199        created_after: date | str | None = None,
200        created_before: date | str | None = None,
201        added_after: date | datetime | str | None = None,
202        added_from: date | datetime | str | None = None,
203        added_before: date | datetime | str | None = None,
204        added_until: date | datetime | str | None = None,
205        modified_after: date | datetime | str | None = None,
206        modified_from: date | datetime | str | None = None,
207        modified_before: date | datetime | str | None = None,
208        modified_until: date | datetime | str | None = None,
209        checksum: str | None = None,
210        page_size: int = 25,
211        page: int | None = None,
212        ordering: str | None = None,
213        descending: bool = False,
214        max_results: int | None = None,
215        on_page: Callable[[int, int | None], None] | None = None,
216    ) -> PagedResult[Document]:
217        """Return a filtered list of documents.
218
219        All tag, correspondent, document-type, storage-path, and custom-field
220        parameters accept either integer IDs or string names.
221
222        When ``page`` is ``None`` (the default), all pages are fetched
223        automatically and ``next`` / ``previous`` in the returned
224        :class:`~easypaperless.models.paged_result.PagedResult` are always
225        ``None`` — even if ``max_results`` truncates the final result set.
226        ``count`` always reflects the server total, not the truncated length.
227        When ``page`` is set to a specific integer, only that one page is
228        fetched and ``next`` / ``previous`` contain the raw API values.
229
230        Args:
231            search: Search string.  Behaviour depends on ``search_mode``.
232            search_mode: How ``search`` is applied.  One of:
233                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
234                ``"original_filename"``.
235            ids: Return only documents whose ID is in this list.
236            tags: Documents must have **all** of these tags (AND semantics).
237            any_tags: Documents must have **at least one** of these tags.
238            exclude_tags: Documents must have **none** of these tags.
239            correspondent: Filter to documents assigned to this correspondent.
240                Pass ``None`` to return only documents with no correspondent set.
241            any_correspondent: Filter to documents assigned to any of these.
242            exclude_correspondents: Exclude documents assigned to any of these.
243            document_type: Filter to documents of exactly this type.
244                Pass ``None`` to return only documents with no document type set.
245            document_type_name_contains: Case-insensitive substring filter on document type name.
246            document_type_name_exact: Case-insensitive exact match on document type name.
247            any_document_type: Filter to documents whose type is any of these.
248            exclude_document_types: Exclude documents whose type is any of these.
249            storage_path: Filter to documents assigned to this storage path.
250                Pass ``None`` to return only documents with no storage path set.
251            any_storage_paths: Filter to documents assigned to any of these paths.
252            exclude_storage_paths: Exclude documents assigned to any of these paths.
253            owner: Filter to documents owned by this user ID.
254                Pass ``None`` to return only documents with no owner set.
255            exclude_owners: Exclude documents owned by any of these user IDs.
256            custom_fields: Documents must have **all** of these custom fields set.
257            any_custom_fields: Documents must have **at least one** of these fields.
258            exclude_custom_fields: Documents must have **none** of these fields.
259            custom_field_query: Filter documents by custom field values using a nested
260                query structure. See the `paperless-ngx API docs
261                <https://docs.paperless-ngx.com/api/#filtering-by-custom-fields>`_ for
262                the query format.
263            archive_serial_number: Filter by exact archive serial number.
264                Pass ``None`` to return only documents with no ASN set.
265            archive_serial_number_from: Filter by ASN >= this value.
266            archive_serial_number_till: Filter by ASN <= this value.
267            created_after: Only documents created after this date.
268                String input must be ISO-8601: ``"YYYY-MM-DD"``.
269            created_before: Only documents created before this date.
270                String input must be ISO-8601: ``"YYYY-MM-DD"``.
271            added_after: Only documents added after this date/time.
272                String input must be ISO-8601: ``"YYYY-MM-DD"`` for date precision or
273                ``"YYYY-MM-DDTHH:MM:SS"`` for datetime precision.
274            added_from: Only documents added on or after this date/time.
275                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
276            added_before: Only documents added before this date/time.
277                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
278            added_until: Only documents added on or before this date/time.
279                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
280            modified_after: Only documents modified after this date/time.
281                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
282            modified_from: Only documents modified on or after this date/time.
283                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
284            modified_before: Only documents modified before this date/time.
285                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
286            modified_until: Only documents modified on or before this date/time.
287                String input must be ISO-8601: ``"YYYY-MM-DD"`` or ``"YYYY-MM-DDTHH:MM:SS"``.
288            checksum: MD5 checksum of the original file (exact match).
289            page_size: Number of results per API page.  Default: ``25``.
290            page: Return only this specific page (1-based).
291            ordering: Field name to sort by.
292            descending: When ``True``, reverses the sort direction.
293            max_results: Stop after collecting this many documents.
294            on_page: Callback invoked after each page fetch.
295
296        Returns:
297            :class:`~easypaperless.models.paged_result.PagedResult` of
298            :class:`~easypaperless.models.documents.Document` objects.
299        """
300        return cast(
301            PagedResult[Document],
302            self._run(
303                self._async_documents.list(
304                    search=search,
305                    search_mode=search_mode,
306                    ids=ids,
307                    tags=tags,
308                    any_tags=any_tags,
309                    exclude_tags=exclude_tags,
310                    correspondent=correspondent,
311                    any_correspondent=any_correspondent,
312                    exclude_correspondents=exclude_correspondents,
313                    document_type=document_type,
314                    document_type_name_contains=document_type_name_contains,
315                    document_type_name_exact=document_type_name_exact,
316                    any_document_type=any_document_type,
317                    exclude_document_types=exclude_document_types,
318                    storage_path=storage_path,
319                    any_storage_paths=any_storage_paths,
320                    exclude_storage_paths=exclude_storage_paths,
321                    owner=owner,
322                    exclude_owners=exclude_owners,
323                    custom_fields=custom_fields,
324                    any_custom_fields=any_custom_fields,
325                    exclude_custom_fields=exclude_custom_fields,
326                    custom_field_query=custom_field_query,
327                    archive_serial_number=archive_serial_number,
328                    archive_serial_number_from=archive_serial_number_from,
329                    archive_serial_number_till=archive_serial_number_till,
330                    created_after=created_after,
331                    created_before=created_before,
332                    added_after=added_after,
333                    added_from=added_from,
334                    added_before=added_before,
335                    added_until=added_until,
336                    modified_after=modified_after,
337                    modified_from=modified_from,
338                    modified_before=modified_before,
339                    modified_until=modified_until,
340                    checksum=checksum,
341                    page_size=page_size,
342                    page=page,
343                    ordering=ordering,
344                    descending=descending,
345                    max_results=max_results,
346                    on_page=on_page,
347                )
348            ),
349        )

Return a filtered list of documents.

All tag, correspondent, document-type, storage-path, and custom-field parameters accept either integer IDs or string names.

When page is None (the default), all pages are fetched automatically and next / previous in the returned ~easypaperless.models.paged_result.PagedResult are always None — even if max_results truncates the final result set. count always reflects the server total, not the truncated length. When page is set to a specific integer, only that one page is fetched and next / previous contain the raw API values.

Arguments:
  • search: Search string. Behaviour depends on search_mode.
  • search_mode: How search is applied. One of: "title_or_content" (default), "title", "query", "original_filename".
  • ids: Return only documents whose ID is in this list.
  • tags: Documents must have all of these tags (AND semantics).
  • any_tags: Documents must have at least one of these tags.
  • exclude_tags: Documents must have none of these tags.
  • correspondent: Filter to documents assigned to this correspondent. Pass None to return only documents with no correspondent set.
  • any_correspondent: Filter to documents assigned to any of these.
  • exclude_correspondents: Exclude documents assigned to any of these.
  • document_type: Filter to documents of exactly this type. Pass None to return only documents with no document type set.
  • document_type_name_contains: Case-insensitive substring filter on document type name.
  • document_type_name_exact: Case-insensitive exact match on document type name.
  • any_document_type: Filter to documents whose type is any of these.
  • exclude_document_types: Exclude documents whose type is any of these.
  • storage_path: Filter to documents assigned to this storage path. Pass None to return only documents with no storage path set.
  • any_storage_paths: Filter to documents assigned to any of these paths.
  • exclude_storage_paths: Exclude documents assigned to any of these paths.
  • owner: Filter to documents owned by this user ID. Pass None to return only documents with no owner set.
  • exclude_owners: Exclude documents owned by any of these user IDs.
  • custom_fields: Documents must have all of these custom fields set.
  • any_custom_fields: Documents must have at least one of these fields.
  • exclude_custom_fields: Documents must have none of these fields.
  • custom_field_query: Filter documents by custom field values using a nested query structure. See the paperless-ngx API docs for the query format.
  • archive_serial_number: Filter by exact archive serial number. Pass None to return only documents with no ASN set.
  • archive_serial_number_from: Filter by ASN >= this value.
  • archive_serial_number_till: Filter by ASN <= this value.
  • created_after: Only documents created after this date. String input must be ISO-8601: "YYYY-MM-DD".
  • created_before: Only documents created before this date. String input must be ISO-8601: "YYYY-MM-DD".
  • added_after: Only documents added after this date/time. String input must be ISO-8601: "YYYY-MM-DD" for date precision or "YYYY-MM-DDTHH:MM:SS" for datetime precision.
  • added_from: Only documents added on or after this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • added_before: Only documents added before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • added_until: Only documents added on or before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_after: Only documents modified after this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_from: Only documents modified on or after this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_before: Only documents modified before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • modified_until: Only documents modified on or before this date/time. String input must be ISO-8601: "YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS".
  • checksum: MD5 checksum of the original file (exact match).
  • page_size: Number of results per API page. Default: 25.
  • page: Return only this specific page (1-based).
  • ordering: Field name to sort by.
  • descending: When True, reverses the sort direction.
  • max_results: Stop after collecting this many documents.
  • on_page: Callback invoked after each page fetch.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.Document objects.

def update( self, id: int, *, title: str | easypaperless.Unset = UNSET, content: str | easypaperless.Unset = UNSET, created: datetime.date | str | None | easypaperless.Unset = UNSET, correspondent: int | str | None | easypaperless.Unset = UNSET, document_type: int | str | None | easypaperless.Unset = UNSET, storage_path: int | str | None | easypaperless.Unset = UNSET, tags: Union[List[Union[str, int]], NoneType, easypaperless.Unset] = UNSET, archive_serial_number: int | None | easypaperless.Unset = UNSET, custom_fields: Union[List[dict[str, Any]], NoneType, easypaperless.Unset] = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET, remove_inbox_tags: bool | None | easypaperless.Unset = UNSET) -> easypaperless.Document:
351    def update(
352        self,
353        id: int,
354        *,
355        title: str | Unset = UNSET,
356        content: str | Unset = UNSET,
357        created: date | str | None | Unset = UNSET,
358        correspondent: int | str | None | Unset = UNSET,
359        document_type: int | str | None | Unset = UNSET,
360        storage_path: int | str | None | Unset = UNSET,
361        tags: List[int | str] | None | Unset = UNSET,
362        archive_serial_number: int | None | Unset = UNSET,
363        custom_fields: List[dict[str, Any]] | None | Unset = UNSET,
364        owner: int | None | Unset = UNSET,
365        set_permissions: SetPermissions | None | Unset = UNSET,
366        remove_inbox_tags: bool | None | Unset = UNSET,
367    ) -> Document:
368        """Partially update a document (PATCH semantics).
369
370        Args:
371            id: Numeric ID of the document to update.
372            title: New document title.
373            content: OCR text content of the document.
374            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
375                :class:`~datetime.date` object.
376            correspondent: Correspondent to assign, as an ID or name.
377                Pass ``None`` to clear the correspondent.
378            document_type: Document type to assign, as an ID or name.
379                Pass ``None`` to clear the document type.
380            storage_path: Storage path to assign, as an ID or name.
381                Pass ``None`` to clear the storage path.
382            tags: Full replacement list of tags (IDs or names).
383            archive_serial_number: Archive serial number to assign.
384                Pass ``None`` to clear the archive serial number.
385            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
386            owner: Numeric user ID to assign as document owner.
387                Pass ``None`` to clear the owner.
388            set_permissions: Explicit view/change permission sets.
389                Pass ``None`` to clear all permissions (overwrite with empty).
390                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
391            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
392
393        Returns:
394            The updated :class:`~easypaperless.models.documents.Document`.
395        """
396        return cast(
397            Document,
398            self._run(
399                self._async_documents.update(
400                    id,
401                    title=title,
402                    content=content,
403                    created=created,
404                    correspondent=correspondent,
405                    document_type=document_type,
406                    storage_path=storage_path,
407                    tags=tags,
408                    archive_serial_number=archive_serial_number,
409                    custom_fields=custom_fields,
410                    owner=owner,
411                    set_permissions=set_permissions,
412                    remove_inbox_tags=remove_inbox_tags,
413                )
414            ),
415        )

Partially update a document (PATCH semantics).

Arguments:
  • id: Numeric ID of the document to update.
  • title: New document title.
  • content: OCR text content of the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear the correspondent.
  • document_type: Document type to assign, as an ID or name. Pass None to clear the document type.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear the storage path.
  • tags: Full replacement list of tags (IDs or names).
  • archive_serial_number: Archive serial number to assign. Pass None to clear the archive serial number.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • owner: Numeric user ID to assign as document owner. Pass None to clear the owner.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • remove_inbox_tags: When True, removes all inbox tags from the document.
Returns:

The updated ~easypaperless.models.documents.Document.

def delete(self, id: int) -> None:
417    def delete(self, id: int) -> None:
418        """Permanently delete a document.
419
420        Args:
421            id: Numeric ID of the document to delete.
422
423        Raises:
424            ~easypaperless.exceptions.NotFoundError: If no document exists
425                with that ID.
426        """
427        self._run(self._async_documents.delete(id))

Permanently delete a document.

Arguments:
  • id: Numeric ID of the document to delete.
Raises:
def download(self, id: int, *, original: bool = False) -> bytes:
429    def download(self, id: int, *, original: bool = False) -> bytes:
430        """Download the binary content of a document.
431
432        Args:
433            id: Numeric ID of the document to download.
434            original: If ``False`` *(default)*, returns the archived PDF
435                (``GET /documents/{id}/download/``).
436                If ``True``, returns the original uploaded file
437                (``GET /documents/{id}/download/?original=true``).
438
439        Returns:
440            Raw file bytes.
441        """
442        return cast(bytes, self._run(self._async_documents.download(id, original=original)))

Download the binary content of a document.

Arguments:
  • id: Numeric ID of the document to download.
  • original: If False (default), returns the archived PDF (GET /documents/{id}/download/). If True, returns the original uploaded file (GET /documents/{id}/download/?original=true).
Returns:

Raw file bytes.

def thumbnail(self, id: int) -> bytes:
444    def thumbnail(self, id: int) -> bytes:
445        """Fetch the thumbnail image of a document.
446
447        Args:
448            id: Numeric ID of the document whose thumbnail to retrieve.
449
450        Returns:
451            Raw binary content of the thumbnail image.
452
453        Raises:
454            ~easypaperless.exceptions.NotFoundError: If no document exists
455                with that ID.
456            ~easypaperless.exceptions.ServerError: If the server returns an
457                HTML page (e.g. an auth redirect) instead of the image.
458        """
459        return cast(bytes, self._run(self._async_documents.thumbnail(id)))

Fetch the thumbnail image of a document.

Arguments:
  • id: Numeric ID of the document whose thumbnail to retrieve.
Returns:

Raw binary content of the thumbnail image.

Raises:
def upload( self, file: str | pathlib._local.Path, *, title: str | easypaperless.Unset = UNSET, created: datetime.date | str | None = None, correspondent: int | str | None | easypaperless.Unset = UNSET, document_type: int | str | None | easypaperless.Unset = UNSET, storage_path: int | str | None | easypaperless.Unset = UNSET, tags: Optional[List[Union[str, int]]] = None, archive_serial_number: int | None | easypaperless.Unset = UNSET, custom_fields: Optional[List[dict[str, Any]]] = None, wait: bool = False, poll_interval: float | None = None, poll_timeout: float | None = None) -> str | easypaperless.Document:
461    def upload(
462        self,
463        file: str | Path,
464        *,
465        title: str | Unset = UNSET,
466        created: date | str | None = None,
467        correspondent: int | str | None | Unset = UNSET,
468        document_type: int | str | None | Unset = UNSET,
469        storage_path: int | str | None | Unset = UNSET,
470        tags: List[int | str] | None = None,
471        archive_serial_number: int | None | Unset = UNSET,
472        custom_fields: List[dict[str, Any]] | None = None,
473        wait: bool = False,
474        poll_interval: float | None = None,
475        poll_timeout: float | None = None,
476    ) -> str | Document:
477        """Upload a document to paperless-ngx.
478
479        Args:
480            file: Path to the file to upload.
481            title: Title to assign to the document.
482            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
483                :class:`~datetime.date` object.
484            correspondent: Correspondent to assign, as an ID or name.
485            document_type: Document type to assign, as an ID or name.
486            storage_path: Storage path to assign, as an ID or name.
487            tags: Tags to assign, as IDs or names.
488            archive_serial_number: Archive serial number to assign.
489            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
490            wait: If ``False`` *(default)*, returns immediately with the task ID.
491                If ``True``, polls until processing completes.
492            poll_interval: Seconds between task-status checks while waiting for
493                processing to complete (requires ``wait=True``). Overrides the
494                client-level default. When omitted, falls back to the client-level
495                ``poll_interval`` (``2.0`` s unless changed at construction).
496            poll_timeout: Maximum seconds to wait before raising
497                :exc:`~easypaperless.exceptions.TaskTimeoutError` (requires
498                ``wait=True``). Overrides the client-level default. When omitted,
499                falls back to the client-level ``poll_timeout`` (``60.0`` s unless
500                changed at construction).
501
502        Returns:
503            The Celery task ID string when ``wait=False``, or the fully
504            processed :class:`~easypaperless.models.documents.Document`
505            when ``wait=True``.
506
507        Raises:
508            ~easypaperless.exceptions.UploadError: If processing fails.
509            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
510        """
511        return cast(
512            str | Document,
513            self._run(
514                self._async_documents.upload(
515                    file,
516                    title=title,
517                    created=created,
518                    correspondent=correspondent,
519                    document_type=document_type,
520                    storage_path=storage_path,
521                    tags=tags,
522                    archive_serial_number=archive_serial_number,
523                    custom_fields=custom_fields,
524                    wait=wait,
525                    poll_interval=poll_interval,
526                    poll_timeout=poll_timeout,
527                )
528            ),
529        )

Upload a document to paperless-ngx.

Arguments:
  • file: Path to the file to upload.
  • title: Title to assign to the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name.
  • document_type: Document type to assign, as an ID or name.
  • storage_path: Storage path to assign, as an ID or name.
  • tags: Tags to assign, as IDs or names.
  • archive_serial_number: Archive serial number to assign.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • wait: If False (default), returns immediately with the task ID. If True, polls until processing completes.
  • poll_interval: Seconds between task-status checks while waiting for processing to complete (requires wait=True). Overrides the client-level default. When omitted, falls back to the client-level poll_interval (2.0 s unless changed at construction).
  • poll_timeout: Maximum seconds to wait before raising ~easypaperless.exceptions.TaskTimeoutError (requires wait=True). Overrides the client-level default. When omitted, falls back to the client-level poll_timeout (60.0 s unless changed at construction).
Returns:

The Celery task ID string when wait=False, or the fully processed ~easypaperless.models.documents.Document when wait=True.

Raises:
def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
531    def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
532        """Add a tag to multiple documents in a single request.
533
534        Args:
535            document_ids: List of document IDs to tag.
536            tag: Tag to add, as an ID or name.
537        """
538        self._run(self._async_documents.bulk_add_tag(document_ids, tag))

Add a tag to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to tag.
  • tag: Tag to add, as an ID or name.
def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
540    def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
541        """Remove a tag from multiple documents in a single request.
542
543        Args:
544            document_ids: List of document IDs to un-tag.
545            tag: Tag to remove, as an ID or name.
546        """
547        self._run(self._async_documents.bulk_remove_tag(document_ids, tag))

Remove a tag from multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to un-tag.
  • tag: Tag to remove, as an ID or name.
def bulk_modify_tags( self, document_ids: List[int], *, add_tags: Optional[List[Union[str, int]]] = None, remove_tags: Optional[List[Union[str, int]]] = None) -> None:
549    def bulk_modify_tags(
550        self,
551        document_ids: List[int],
552        *,
553        add_tags: List[int | str] | None = None,
554        remove_tags: List[int | str] | None = None,
555    ) -> None:
556        """Add and/or remove tags on multiple documents atomically.
557
558        Args:
559            document_ids: List of document IDs to modify.
560            add_tags: Tags to add, as IDs or names.
561            remove_tags: Tags to remove, as IDs or names.
562        """
563        self._run(
564            self._async_documents.bulk_modify_tags(
565                document_ids, add_tags=add_tags, remove_tags=remove_tags
566            )
567        )

Add and/or remove tags on multiple documents atomically.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_tags: Tags to add, as IDs or names.
  • remove_tags: Tags to remove, as IDs or names.
def bulk_delete(self, document_ids: List[int]) -> None:
569    def bulk_delete(self, document_ids: List[int]) -> None:
570        """Permanently delete multiple documents in a single request.
571
572        Args:
573            document_ids: List of document IDs to delete.
574        """
575        self._run(self._async_documents.bulk_delete(document_ids))

Permanently delete multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to delete.
def bulk_set_correspondent(self, document_ids: List[int], correspondent: int | str | None) -> None:
577    def bulk_set_correspondent(
578        self, document_ids: List[int], correspondent: int | str | None
579    ) -> None:
580        """Assign a correspondent to multiple documents in a single request.
581
582        Args:
583            document_ids: List of document IDs to modify.
584            correspondent: Correspondent to assign, as an ID or name.
585                Pass ``None`` to clear.
586        """
587        self._run(self._async_documents.bulk_set_correspondent(document_ids, correspondent))

Assign a correspondent to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear.
def bulk_set_document_type(self, document_ids: List[int], document_type: int | str | None) -> None:
589    def bulk_set_document_type(
590        self, document_ids: List[int], document_type: int | str | None
591    ) -> None:
592        """Assign a document type to multiple documents in a single request.
593
594        Args:
595            document_ids: List of document IDs to modify.
596            document_type: Document type to assign, as an ID or name.
597                Pass ``None`` to clear.
598        """
599        self._run(self._async_documents.bulk_set_document_type(document_ids, document_type))

Assign a document type to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • document_type: Document type to assign, as an ID or name. Pass None to clear.
def bulk_set_storage_path(self, document_ids: List[int], storage_path: int | str | None) -> None:
601    def bulk_set_storage_path(
602        self, document_ids: List[int], storage_path: int | str | None
603    ) -> None:
604        """Assign a storage path to multiple documents in a single request.
605
606        Args:
607            document_ids: List of document IDs to modify.
608            storage_path: Storage path to assign, as an ID or name.
609                Pass ``None`` to clear.
610        """
611        self._run(self._async_documents.bulk_set_storage_path(document_ids, storage_path))

Assign a storage path to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear.
def bulk_modify_custom_fields( self, document_ids: List[int], *, add_fields: Optional[List[dict[str, Any]]] = None, remove_fields: Optional[List[int]] = None) -> None:
613    def bulk_modify_custom_fields(
614        self,
615        document_ids: List[int],
616        *,
617        add_fields: List[dict[str, Any]] | None = None,
618        remove_fields: List[int] | None = None,
619    ) -> None:
620        """Add and/or remove custom field values on multiple documents.
621
622        Args:
623            document_ids: List of document IDs to modify.
624            add_fields: Custom-field value dicts to add.
625            remove_fields: Custom-field IDs whose values should be removed.
626        """
627        self._run(
628            self._async_documents.bulk_modify_custom_fields(
629                document_ids, add_fields=add_fields, remove_fields=remove_fields
630            )
631        )

Add and/or remove custom field values on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_fields: Custom-field value dicts to add.
  • remove_fields: Custom-field IDs whose values should be removed.
def bulk_set_permissions( self, document_ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
633    def bulk_set_permissions(
634        self,
635        document_ids: List[int],
636        *,
637        set_permissions: SetPermissions | Unset = UNSET,
638        owner: int | None | Unset = UNSET,
639        merge: bool = False,
640    ) -> None:
641        """Set permissions and/or owner on multiple documents.
642
643        Args:
644            document_ids: List of document IDs to modify.
645            set_permissions: Explicit view/change permission sets.
646                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
647            owner: Numeric user ID to assign as document owner.
648                Pass ``None`` to clear the owner.
649                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
650            merge: When ``True``, new permissions are merged with existing ones.
651        """
652        self._run(
653            self._async_documents.bulk_set_permissions(
654                document_ids,
655                set_permissions=set_permissions,
656                owner=owner,
657                merge=merge,
658            )
659        )

Set permissions and/or owner on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as document owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
def bulk_download( self, document_ids: List[int], *, content: Literal['archive', 'originals', 'both'] = 'archive', compression: Literal['none', 'deflated', 'bzip2', 'lzma'] = 'none', follow_formatting: bool = False) -> bytes:
661    def bulk_download(
662        self,
663        document_ids: List[int],
664        *,
665        content: Literal["archive", "originals", "both"] = "archive",
666        compression: Literal["none", "deflated", "bzip2", "lzma"] = "none",
667        follow_formatting: bool = False,
668    ) -> bytes:
669        """Download multiple documents as a single ZIP archive.
670
671        Args:
672            document_ids: List of document IDs to include in the ZIP.
673            content: File variant to include.  One of ``"archive"`` *(default)*,
674                ``"originals"``, or ``"both"``.
675            compression: ZIP compression algorithm.  One of ``"none"`` *(default)*,
676                ``"deflated"``, ``"bzip2"``, or ``"lzma"``.
677            follow_formatting: When ``True``, filenames inside the ZIP follow
678                the storage path formatting configured in paperless-ngx.
679                Default: ``False``.
680
681        Returns:
682            Raw bytes of the ZIP archive.
683        """
684        return cast(
685            bytes,
686            self._run(
687                self._async_documents.bulk_download(
688                    document_ids,
689                    content=content,
690                    compression=compression,
691                    follow_formatting=follow_formatting,
692                )
693            ),
694        )

Download multiple documents as a single ZIP archive.

Arguments:
  • document_ids: List of document IDs to include in the ZIP.
  • content: File variant to include. One of "archive" (default), "originals", or "both".
  • compression: ZIP compression algorithm. One of "none" (default), "deflated", "bzip2", or "lzma".
  • follow_formatting: When True, filenames inside the ZIP follow the storage path formatting configured in paperless-ngx. Default: False.
Returns:

Raw bytes of the ZIP archive.

class SyncNotesResource:
20class SyncNotesResource:
21    """Sync accessor for document notes: ``client.documents.notes``."""
22
23    def __init__(self, async_notes: NotesResource, run: Any) -> None:
24        self._async_notes = async_notes
25        self._run = run
26
27    def list(
28        self,
29        document_id: int,
30        *,
31        page: int | None = None,
32        page_size: int | None = None,
33    ) -> PagedResult[DocumentNote]:
34        """Fetch notes attached to a document.
35
36        When ``page`` is ``None`` (the default), all pages are fetched
37        automatically and ``next`` / ``previous`` in the returned
38        :class:`~easypaperless.models.paged_result.PagedResult` are always
39        ``None``.  When ``page`` is set to a specific integer, only that one
40        page is fetched and ``next`` / ``previous`` contain the raw API values.
41
42        Args:
43            document_id: Numeric ID of the document whose notes to retrieve.
44            page: Return only this specific page (1-based).
45            page_size: Number of results per page.
46
47        Returns:
48            :class:`~easypaperless.models.paged_result.PagedResult` of
49            :class:`~easypaperless.models.documents.DocumentNote` objects,
50            ordered by creation time.
51
52        Raises:
53            ~easypaperless.exceptions.NotFoundError: If no document exists
54                with that ID.
55        """
56        return cast(
57            PagedResult[DocumentNote],
58            self._run(self._async_notes.list(document_id, page=page, page_size=page_size)),
59        )
60
61    def create(self, document_id: int, *, note: str) -> DocumentNote:
62        """Create a new note on a document.
63
64        Args:
65            document_id: Numeric ID of the document to annotate.
66            note: Text content of the note.
67
68        Returns:
69            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
70
71        Raises:
72            ~easypaperless.exceptions.NotFoundError: If no document exists
73                with that ID.
74        """
75        return cast(DocumentNote, self._run(self._async_notes.create(document_id, note=note)))
76
77    def delete(self, document_id: int, note_id: int) -> None:
78        """Delete a note from a document.
79
80        Args:
81            document_id: Numeric ID of the document that owns the note.
82            note_id: Numeric ID of the note to delete.
83
84        Raises:
85            ~easypaperless.exceptions.NotFoundError: If no document or note
86                exists with the given IDs.
87        """
88        self._run(self._async_notes.delete(document_id, note_id))

Sync accessor for document notes: client.documents.notes.

SyncNotesResource( async_notes: NotesResource, run: Any)
23    def __init__(self, async_notes: NotesResource, run: Any) -> None:
24        self._async_notes = async_notes
25        self._run = run
def list( self, document_id: int, *, page: int | None = None, page_size: int | None = None) -> easypaperless.PagedResult[DocumentNote]:
27    def list(
28        self,
29        document_id: int,
30        *,
31        page: int | None = None,
32        page_size: int | None = None,
33    ) -> PagedResult[DocumentNote]:
34        """Fetch notes attached to a document.
35
36        When ``page`` is ``None`` (the default), all pages are fetched
37        automatically and ``next`` / ``previous`` in the returned
38        :class:`~easypaperless.models.paged_result.PagedResult` are always
39        ``None``.  When ``page`` is set to a specific integer, only that one
40        page is fetched and ``next`` / ``previous`` contain the raw API values.
41
42        Args:
43            document_id: Numeric ID of the document whose notes to retrieve.
44            page: Return only this specific page (1-based).
45            page_size: Number of results per page.
46
47        Returns:
48            :class:`~easypaperless.models.paged_result.PagedResult` of
49            :class:`~easypaperless.models.documents.DocumentNote` objects,
50            ordered by creation time.
51
52        Raises:
53            ~easypaperless.exceptions.NotFoundError: If no document exists
54                with that ID.
55        """
56        return cast(
57            PagedResult[DocumentNote],
58            self._run(self._async_notes.list(document_id, page=page, page_size=page_size)),
59        )

Fetch notes attached to a document.

When page is None (the default), all pages are fetched automatically and next / previous in the returned ~easypaperless.models.paged_result.PagedResult are always None. When page is set to a specific integer, only that one page is fetched and next / previous contain the raw API values.

Arguments:
  • document_id: Numeric ID of the document whose notes to retrieve.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.DocumentNote objects, ordered by creation time.

Raises:
def create( self, document_id: int, *, note: str) -> easypaperless.DocumentNote:
61    def create(self, document_id: int, *, note: str) -> DocumentNote:
62        """Create a new note on a document.
63
64        Args:
65            document_id: Numeric ID of the document to annotate.
66            note: Text content of the note.
67
68        Returns:
69            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
70
71        Raises:
72            ~easypaperless.exceptions.NotFoundError: If no document exists
73                with that ID.
74        """
75        return cast(DocumentNote, self._run(self._async_notes.create(document_id, note=note)))

Create a new note on a document.

Arguments:
  • document_id: Numeric ID of the document to annotate.
  • note: Text content of the note.
Returns:

The newly created ~easypaperless.models.documents.DocumentNote.

Raises:
def delete(self, document_id: int, note_id: int) -> None:
77    def delete(self, document_id: int, note_id: int) -> None:
78        """Delete a note from a document.
79
80        Args:
81            document_id: Numeric ID of the document that owns the note.
82            note_id: Numeric ID of the note to delete.
83
84        Raises:
85            ~easypaperless.exceptions.NotFoundError: If no document or note
86                exists with the given IDs.
87        """
88        self._run(self._async_notes.delete(document_id, note_id))

Delete a note from a document.

Arguments:
  • document_id: Numeric ID of the document that owns the note.
  • note_id: Numeric ID of the note to delete.
Raises:
class SyncStoragePathsResource:
 18class SyncStoragePathsResource:
 19    """Sync accessor for storage paths: ``client.storage_paths``."""
 20
 21    def __init__(self, async_storage_paths: StoragePathsResource, run: Any) -> None:
 22        self._async_storage_paths = async_storage_paths
 23        self._run = run
 24
 25    def list(
 26        self,
 27        *,
 28        ids: List[int] | None = None,
 29        name_contains: str | None = None,
 30        name_exact: str | None = None,
 31        path_contains: str | None = None,
 32        path_exact: str | None = None,
 33        page: int | None = None,
 34        page_size: int | None = None,
 35        ordering: str | None = None,
 36        descending: bool = False,
 37    ) -> PagedResult[StoragePath]:
 38        """Return storage paths defined in paperless-ngx.
 39
 40        When ``page`` is ``None`` (the default), all pages are fetched
 41        automatically and ``next`` / ``previous`` in the result are always
 42        ``None``.  When ``page`` is set, only that page is fetched and
 43        ``next`` / ``previous`` reflect the raw API values.
 44
 45        Args:
 46            ids: Return only storage paths whose ID is in this list.
 47            name_contains: Case-insensitive substring filter on name.
 48            name_exact: Case-insensitive exact match on name.
 49            path_contains: Case-insensitive substring filter on path template.
 50            path_exact: Case-insensitive exact match on path template.
 51            page: Return only this specific page (1-based).
 52            page_size: Number of results per page.
 53            ordering: Field to sort by.
 54            descending: When ``True``, reverses the sort direction.
 55
 56        Returns:
 57            :class:`~easypaperless.models.paged_result.PagedResult` of
 58            :class:`~easypaperless.models.storage_paths.StoragePath` objects.
 59        """
 60        return cast(
 61            PagedResult[StoragePath],
 62            self._run(
 63                self._async_storage_paths.list(
 64                    ids=ids,
 65                    name_contains=name_contains,
 66                    name_exact=name_exact,
 67                    path_contains=path_contains,
 68                    path_exact=path_exact,
 69                    page=page,
 70                    page_size=page_size,
 71                    ordering=ordering,
 72                    descending=descending,
 73                )
 74            ),
 75        )
 76
 77    def get(self, id: int) -> StoragePath:
 78        """Fetch a single storage path by its ID.
 79
 80        Args:
 81            id: Numeric storage-path ID.
 82
 83        Returns:
 84            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
 85
 86        Raises:
 87            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
 88        """
 89        return cast(StoragePath, self._run(self._async_storage_paths.get(id)))
 90
 91    def create(
 92        self,
 93        *,
 94        name: str,
 95        path: str | Unset = UNSET,
 96        match: str | Unset = UNSET,
 97        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 98        is_insensitive: bool = True,
 99        owner: int | None | Unset = UNSET,
100        set_permissions: SetPermissions | None | Unset = UNSET,
101    ) -> StoragePath:
102        """Create a new storage path.
103
104        Args:
105            name: Storage-path name. Must be unique.
106            path: Template string for the archive file path.
107            match: Auto-matching pattern.
108            matching_algorithm: Controls how ``match`` is applied.
109                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
110                regular-expression matching.
111            is_insensitive: When ``True``, ``match`` is case-insensitive.
112                Defaults to ``True``, matching the paperless-ngx API default.
113            owner: Numeric user ID to assign as owner.
114            set_permissions: Explicit view/change permission sets.
115                Pass ``None`` to create with empty permissions.
116
117        Returns:
118            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
119        """
120        return cast(
121            StoragePath,
122            self._run(
123                self._async_storage_paths.create(
124                    name=name,
125                    path=path,
126                    match=match,
127                    matching_algorithm=matching_algorithm,
128                    is_insensitive=is_insensitive,
129                    owner=owner,
130                    set_permissions=set_permissions,
131                )
132            ),
133        )
134
135    def update(
136        self,
137        id: int,
138        *,
139        name: str | Unset = UNSET,
140        path: str | Unset = UNSET,
141        match: str | Unset = UNSET,
142        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
143        is_insensitive: bool | Unset = UNSET,
144        owner: int | None | Unset = UNSET,
145        set_permissions: SetPermissions | None | Unset = UNSET,
146    ) -> StoragePath:
147        """Partially update a storage path (PATCH semantics).
148
149        Args:
150            id: Numeric ID of the storage path to update.
151            name: Storage-path name.
152            path: Template string for the archive file path.
153            match: Auto-matching pattern.
154            matching_algorithm: Controls how ``match`` is applied.
155                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
156                regular-expression matching.
157            is_insensitive: When ``True``, ``match`` is case-insensitive.
158            owner: Numeric user ID to assign as owner.
159                Pass ``None`` to clear the owner.
160                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
161            set_permissions: Explicit view/change permission sets.
162                Pass ``None`` to clear all permissions (overwrite with empty).
163                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
164
165        Returns:
166            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
167        """
168        return cast(
169            StoragePath,
170            self._run(
171                self._async_storage_paths.update(
172                    id,
173                    name=name,
174                    path=path,
175                    match=match,
176                    matching_algorithm=matching_algorithm,
177                    is_insensitive=is_insensitive,
178                    owner=owner,
179                    set_permissions=set_permissions,
180                )
181            ),
182        )
183
184    def delete(self, id: int) -> None:
185        """Delete a storage path.
186
187        Args:
188            id: Numeric ID of the storage path to delete.
189
190        Raises:
191            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
192        """
193        self._run(self._async_storage_paths.delete(id))
194
195    def bulk_delete(self, ids: List[int]) -> None:
196        """Permanently delete multiple storage paths in a single request.
197
198        Args:
199            ids: List of storage path IDs to delete.
200        """
201        self._run(self._async_storage_paths.bulk_delete(ids))
202
203    def bulk_set_permissions(
204        self,
205        ids: List[int],
206        *,
207        set_permissions: SetPermissions | Unset = UNSET,
208        owner: int | None | Unset = UNSET,
209        merge: bool = False,
210    ) -> None:
211        """Set permissions and/or owner on multiple storage paths.
212
213        Args:
214            ids: List of storage path IDs to modify.
215            set_permissions: Explicit view/change permission sets.
216                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
217            owner: Numeric user ID to assign as owner.
218                Pass ``None`` to clear the owner.
219                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
220            merge: When ``True``, new permissions are merged with existing ones.
221        """
222        self._run(
223            self._async_storage_paths.bulk_set_permissions(
224                ids, set_permissions=set_permissions, owner=owner, merge=merge
225            )
226        )

Sync accessor for storage paths: client.storage_paths.

SyncStoragePathsResource( async_storage_paths: StoragePathsResource, run: Any)
21    def __init__(self, async_storage_paths: StoragePathsResource, run: Any) -> None:
22        self._async_storage_paths = async_storage_paths
23        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, path_contains: str | None = None, path_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[StoragePath]:
25    def list(
26        self,
27        *,
28        ids: List[int] | None = None,
29        name_contains: str | None = None,
30        name_exact: str | None = None,
31        path_contains: str | None = None,
32        path_exact: str | None = None,
33        page: int | None = None,
34        page_size: int | None = None,
35        ordering: str | None = None,
36        descending: bool = False,
37    ) -> PagedResult[StoragePath]:
38        """Return storage paths defined in paperless-ngx.
39
40        When ``page`` is ``None`` (the default), all pages are fetched
41        automatically and ``next`` / ``previous`` in the result are always
42        ``None``.  When ``page`` is set, only that page is fetched and
43        ``next`` / ``previous`` reflect the raw API values.
44
45        Args:
46            ids: Return only storage paths whose ID is in this list.
47            name_contains: Case-insensitive substring filter on name.
48            name_exact: Case-insensitive exact match on name.
49            path_contains: Case-insensitive substring filter on path template.
50            path_exact: Case-insensitive exact match on path template.
51            page: Return only this specific page (1-based).
52            page_size: Number of results per page.
53            ordering: Field to sort by.
54            descending: When ``True``, reverses the sort direction.
55
56        Returns:
57            :class:`~easypaperless.models.paged_result.PagedResult` of
58            :class:`~easypaperless.models.storage_paths.StoragePath` objects.
59        """
60        return cast(
61            PagedResult[StoragePath],
62            self._run(
63                self._async_storage_paths.list(
64                    ids=ids,
65                    name_contains=name_contains,
66                    name_exact=name_exact,
67                    path_contains=path_contains,
68                    path_exact=path_exact,
69                    page=page,
70                    page_size=page_size,
71                    ordering=ordering,
72                    descending=descending,
73                )
74            ),
75        )

Return storage paths defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only storage paths whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • path_contains: Case-insensitive substring filter on path template.
  • path_exact: Case-insensitive exact match on path template.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.storage_paths.StoragePath objects.

def get(self, id: int) -> easypaperless.StoragePath:
77    def get(self, id: int) -> StoragePath:
78        """Fetch a single storage path by its ID.
79
80        Args:
81            id: Numeric storage-path ID.
82
83        Returns:
84            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
85
86        Raises:
87            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
88        """
89        return cast(StoragePath, self._run(self._async_storage_paths.get(id)))

Fetch a single storage path by its ID.

Arguments:
  • id: Numeric storage-path ID.
Returns:

The ~easypaperless.models.storage_paths.StoragePath with the given ID.

Raises:
def create( self, *, name: str, path: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.StoragePath:
 91    def create(
 92        self,
 93        *,
 94        name: str,
 95        path: str | Unset = UNSET,
 96        match: str | Unset = UNSET,
 97        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 98        is_insensitive: bool = True,
 99        owner: int | None | Unset = UNSET,
100        set_permissions: SetPermissions | None | Unset = UNSET,
101    ) -> StoragePath:
102        """Create a new storage path.
103
104        Args:
105            name: Storage-path name. Must be unique.
106            path: Template string for the archive file path.
107            match: Auto-matching pattern.
108            matching_algorithm: Controls how ``match`` is applied.
109                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
110                regular-expression matching.
111            is_insensitive: When ``True``, ``match`` is case-insensitive.
112                Defaults to ``True``, matching the paperless-ngx API default.
113            owner: Numeric user ID to assign as owner.
114            set_permissions: Explicit view/change permission sets.
115                Pass ``None`` to create with empty permissions.
116
117        Returns:
118            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
119        """
120        return cast(
121            StoragePath,
122            self._run(
123                self._async_storage_paths.create(
124                    name=name,
125                    path=path,
126                    match=match,
127                    matching_algorithm=matching_algorithm,
128                    is_insensitive=is_insensitive,
129                    owner=owner,
130                    set_permissions=set_permissions,
131                )
132            ),
133        )

Create a new storage path.

Arguments:
  • name: Storage-path name. Must be unique.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.storage_paths.StoragePath.

def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, path: str | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.StoragePath:
135    def update(
136        self,
137        id: int,
138        *,
139        name: str | Unset = UNSET,
140        path: str | Unset = UNSET,
141        match: str | Unset = UNSET,
142        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
143        is_insensitive: bool | Unset = UNSET,
144        owner: int | None | Unset = UNSET,
145        set_permissions: SetPermissions | None | Unset = UNSET,
146    ) -> StoragePath:
147        """Partially update a storage path (PATCH semantics).
148
149        Args:
150            id: Numeric ID of the storage path to update.
151            name: Storage-path name.
152            path: Template string for the archive file path.
153            match: Auto-matching pattern.
154            matching_algorithm: Controls how ``match`` is applied.
155                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
156                regular-expression matching.
157            is_insensitive: When ``True``, ``match`` is case-insensitive.
158            owner: Numeric user ID to assign as owner.
159                Pass ``None`` to clear the owner.
160                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
161            set_permissions: Explicit view/change permission sets.
162                Pass ``None`` to clear all permissions (overwrite with empty).
163                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
164
165        Returns:
166            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
167        """
168        return cast(
169            StoragePath,
170            self._run(
171                self._async_storage_paths.update(
172                    id,
173                    name=name,
174                    path=path,
175                    match=match,
176                    matching_algorithm=matching_algorithm,
177                    is_insensitive=is_insensitive,
178                    owner=owner,
179                    set_permissions=set_permissions,
180                )
181            ),
182        )

Partially update a storage path (PATCH semantics).

Arguments:
  • id: Numeric ID of the storage path to update.
  • name: Storage-path name.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.storage_paths.StoragePath.

def delete(self, id: int) -> None:
184    def delete(self, id: int) -> None:
185        """Delete a storage path.
186
187        Args:
188            id: Numeric ID of the storage path to delete.
189
190        Raises:
191            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
192        """
193        self._run(self._async_storage_paths.delete(id))

Delete a storage path.

Arguments:
  • id: Numeric ID of the storage path to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
195    def bulk_delete(self, ids: List[int]) -> None:
196        """Permanently delete multiple storage paths in a single request.
197
198        Args:
199            ids: List of storage path IDs to delete.
200        """
201        self._run(self._async_storage_paths.bulk_delete(ids))

Permanently delete multiple storage paths in a single request.

Arguments:
  • ids: List of storage path IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
203    def bulk_set_permissions(
204        self,
205        ids: List[int],
206        *,
207        set_permissions: SetPermissions | Unset = UNSET,
208        owner: int | None | Unset = UNSET,
209        merge: bool = False,
210    ) -> None:
211        """Set permissions and/or owner on multiple storage paths.
212
213        Args:
214            ids: List of storage path IDs to modify.
215            set_permissions: Explicit view/change permission sets.
216                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
217            owner: Numeric user ID to assign as owner.
218                Pass ``None`` to clear the owner.
219                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
220            merge: When ``True``, new permissions are merged with existing ones.
221        """
222        self._run(
223            self._async_storage_paths.bulk_set_permissions(
224                ids, set_permissions=set_permissions, owner=owner, merge=merge
225            )
226        )

Set permissions and/or owner on multiple storage paths.

Arguments:
  • ids: List of storage path IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class SyncTagsResource:
 18class SyncTagsResource:
 19    """Sync accessor for tags: ``client.tags``."""
 20
 21    def __init__(self, async_tags: TagsResource, run: Any) -> None:
 22        self._async_tags = async_tags
 23        self._run = run
 24
 25    def list(
 26        self,
 27        *,
 28        ids: List[int] | None = None,
 29        name_contains: str | None = None,
 30        name_exact: str | None = None,
 31        page: int | None = None,
 32        page_size: int | None = None,
 33        ordering: str | None = None,
 34        descending: bool = False,
 35    ) -> PagedResult[Tag]:
 36        """Return tags defined in paperless-ngx.
 37
 38        When ``page`` is ``None`` (the default), all pages are fetched
 39        automatically and ``next`` / ``previous`` in the result are always
 40        ``None``.  When ``page`` is set, only that page is fetched and
 41        ``next`` / ``previous`` reflect the raw API values.
 42
 43        Args:
 44            ids: Return only tags whose ID is in this list.
 45            name_contains: Case-insensitive substring filter on tag name.
 46            name_exact: Case-insensitive exact match on tag name.
 47            page: Return only this specific page (1-based).
 48            page_size: Number of results per page.
 49            ordering: Field to sort by.
 50            descending: When ``True``, reverses the sort direction.
 51
 52        Returns:
 53            :class:`~easypaperless.models.paged_result.PagedResult` of
 54            :class:`~easypaperless.models.tags.Tag` objects.
 55        """
 56        return cast(
 57            PagedResult[Tag],
 58            self._run(
 59                self._async_tags.list(
 60                    ids=ids,
 61                    name_contains=name_contains,
 62                    name_exact=name_exact,
 63                    page=page,
 64                    page_size=page_size,
 65                    ordering=ordering,
 66                    descending=descending,
 67                )
 68            ),
 69        )
 70
 71    def get(self, id: int) -> Tag:
 72        """Fetch a single tag by its ID.
 73
 74        Args:
 75            id: Numeric tag ID.
 76
 77        Returns:
 78            The :class:`~easypaperless.models.tags.Tag` with the given ID.
 79
 80        Raises:
 81            ~easypaperless.exceptions.NotFoundError: If no tag exists with
 82                that ID.
 83        """
 84        return cast(Tag, self._run(self._async_tags.get(id)))
 85
 86    def create(
 87        self,
 88        *,
 89        name: str,
 90        color: str | Unset = UNSET,
 91        is_inbox_tag: bool | Unset = UNSET,
 92        match: str | Unset = UNSET,
 93        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 94        is_insensitive: bool = True,
 95        parent: int | None | Unset = UNSET,
 96        owner: int | None | Unset = UNSET,
 97        set_permissions: SetPermissions | None | Unset = UNSET,
 98    ) -> Tag:
 99        """Create a new tag.
100
101        Args:
102            name: Tag name. Must be unique.
103            color: Background colour as a CSS hex string.
104            is_inbox_tag: When ``True``, newly ingested documents get this tag.
105            match: Auto-matching pattern.
106            matching_algorithm: Controls how ``match`` is applied.
107                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
108                regular-expression matching.
109            is_insensitive: When ``True``, ``match`` is case-insensitive.
110                Defaults to ``True``, matching the paperless-ngx API default.
111            parent: ID of parent tag for hierarchical trees.
112            owner: Numeric user ID to assign as owner.
113            set_permissions: Explicit view/change permission sets.
114                Pass ``None`` to create with empty permissions.
115
116        Returns:
117            The newly created :class:`~easypaperless.models.tags.Tag`.
118        """
119        return cast(
120            Tag,
121            self._run(
122                self._async_tags.create(
123                    name=name,
124                    color=color,
125                    is_inbox_tag=is_inbox_tag,
126                    match=match,
127                    matching_algorithm=matching_algorithm,
128                    is_insensitive=is_insensitive,
129                    parent=parent,
130                    owner=owner,
131                    set_permissions=set_permissions,
132                )
133            ),
134        )
135
136    def update(
137        self,
138        id: int,
139        *,
140        name: str | Unset = UNSET,
141        color: str | Unset = UNSET,
142        is_inbox_tag: bool | Unset = UNSET,
143        match: str | Unset = UNSET,
144        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
145        is_insensitive: bool | Unset = UNSET,
146        parent: int | None | Unset = UNSET,
147        owner: int | None | Unset = UNSET,
148        set_permissions: SetPermissions | None | Unset = UNSET,
149    ) -> Tag:
150        """Partially update a tag (PATCH semantics).
151
152        Args:
153            id: Numeric ID of the tag to update.
154            name: Tag name.
155            color: Background colour as a CSS hex string.
156            is_inbox_tag: When ``True``, newly ingested documents get this tag.
157            match: Auto-matching pattern.
158            matching_algorithm: Controls how ``match`` is applied.
159                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
160                regular-expression matching.
161            is_insensitive: When ``True``, ``match`` is case-insensitive.
162            parent: ID of parent tag.
163                Pass ``None`` to clear (make root tag).
164                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
165            owner: Numeric user ID to assign as owner.
166                Pass ``None`` to clear the owner.
167                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
168            set_permissions: Explicit view/change permission sets.
169                Pass ``None`` to clear all permissions (overwrite with empty).
170                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
171
172        Returns:
173            The updated :class:`~easypaperless.models.tags.Tag`.
174        """
175        return cast(
176            Tag,
177            self._run(
178                self._async_tags.update(
179                    id,
180                    name=name,
181                    color=color,
182                    is_inbox_tag=is_inbox_tag,
183                    match=match,
184                    matching_algorithm=matching_algorithm,
185                    is_insensitive=is_insensitive,
186                    parent=parent,
187                    owner=owner,
188                    set_permissions=set_permissions,
189                )
190            ),
191        )
192
193    def delete(self, id: int) -> None:
194        """Delete a tag.
195
196        Args:
197            id: Numeric ID of the tag to delete.
198
199        Raises:
200            ~easypaperless.exceptions.NotFoundError: If no tag exists with
201                that ID.
202        """
203        self._run(self._async_tags.delete(id))
204
205    def bulk_delete(self, ids: List[int]) -> None:
206        """Permanently delete multiple tags in a single request.
207
208        Args:
209            ids: List of tag IDs to delete.
210        """
211        self._run(self._async_tags.bulk_delete(ids))
212
213    def bulk_set_permissions(
214        self,
215        ids: List[int],
216        *,
217        set_permissions: SetPermissions | Unset = UNSET,
218        owner: int | None | Unset = UNSET,
219        merge: bool = False,
220    ) -> None:
221        """Set permissions and/or owner on multiple tags.
222
223        Args:
224            ids: List of tag IDs to modify.
225            set_permissions: Explicit view/change permission sets.
226                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
227            owner: Numeric user ID to assign as owner.
228                Pass ``None`` to clear the owner.
229                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
230            merge: When ``True``, new permissions are merged with existing ones.
231        """
232        self._run(
233            self._async_tags.bulk_set_permissions(
234                ids, set_permissions=set_permissions, owner=owner, merge=merge
235            )
236        )

Sync accessor for tags: client.tags.

SyncTagsResource( async_tags: TagsResource, run: Any)
21    def __init__(self, async_tags: TagsResource, run: Any) -> None:
22        self._async_tags = async_tags
23        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> easypaperless.PagedResult[Tag]:
25    def list(
26        self,
27        *,
28        ids: List[int] | None = None,
29        name_contains: str | None = None,
30        name_exact: str | None = None,
31        page: int | None = None,
32        page_size: int | None = None,
33        ordering: str | None = None,
34        descending: bool = False,
35    ) -> PagedResult[Tag]:
36        """Return tags defined in paperless-ngx.
37
38        When ``page`` is ``None`` (the default), all pages are fetched
39        automatically and ``next`` / ``previous`` in the result are always
40        ``None``.  When ``page`` is set, only that page is fetched and
41        ``next`` / ``previous`` reflect the raw API values.
42
43        Args:
44            ids: Return only tags whose ID is in this list.
45            name_contains: Case-insensitive substring filter on tag name.
46            name_exact: Case-insensitive exact match on tag name.
47            page: Return only this specific page (1-based).
48            page_size: Number of results per page.
49            ordering: Field to sort by.
50            descending: When ``True``, reverses the sort direction.
51
52        Returns:
53            :class:`~easypaperless.models.paged_result.PagedResult` of
54            :class:`~easypaperless.models.tags.Tag` objects.
55        """
56        return cast(
57            PagedResult[Tag],
58            self._run(
59                self._async_tags.list(
60                    ids=ids,
61                    name_contains=name_contains,
62                    name_exact=name_exact,
63                    page=page,
64                    page_size=page_size,
65                    ordering=ordering,
66                    descending=descending,
67                )
68            ),
69        )

Return tags defined in paperless-ngx.

When page is None (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • ids: Return only tags whose ID is in this list.
  • name_contains: Case-insensitive substring filter on tag name.
  • name_exact: Case-insensitive exact match on tag name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.tags.Tag objects.

def get(self, id: int) -> easypaperless.Tag:
71    def get(self, id: int) -> Tag:
72        """Fetch a single tag by its ID.
73
74        Args:
75            id: Numeric tag ID.
76
77        Returns:
78            The :class:`~easypaperless.models.tags.Tag` with the given ID.
79
80        Raises:
81            ~easypaperless.exceptions.NotFoundError: If no tag exists with
82                that ID.
83        """
84        return cast(Tag, self._run(self._async_tags.get(id)))

Fetch a single tag by its ID.

Arguments:
  • id: Numeric tag ID.
Returns:

The ~easypaperless.models.tags.Tag with the given ID.

Raises:
def create( self, *, name: str, color: str | easypaperless.Unset = UNSET, is_inbox_tag: bool | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool = True, parent: int | None | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Tag:
 86    def create(
 87        self,
 88        *,
 89        name: str,
 90        color: str | Unset = UNSET,
 91        is_inbox_tag: bool | Unset = UNSET,
 92        match: str | Unset = UNSET,
 93        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
 94        is_insensitive: bool = True,
 95        parent: int | None | Unset = UNSET,
 96        owner: int | None | Unset = UNSET,
 97        set_permissions: SetPermissions | None | Unset = UNSET,
 98    ) -> Tag:
 99        """Create a new tag.
100
101        Args:
102            name: Tag name. Must be unique.
103            color: Background colour as a CSS hex string.
104            is_inbox_tag: When ``True``, newly ingested documents get this tag.
105            match: Auto-matching pattern.
106            matching_algorithm: Controls how ``match`` is applied.
107                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
108                regular-expression matching.
109            is_insensitive: When ``True``, ``match`` is case-insensitive.
110                Defaults to ``True``, matching the paperless-ngx API default.
111            parent: ID of parent tag for hierarchical trees.
112            owner: Numeric user ID to assign as owner.
113            set_permissions: Explicit view/change permission sets.
114                Pass ``None`` to create with empty permissions.
115
116        Returns:
117            The newly created :class:`~easypaperless.models.tags.Tag`.
118        """
119        return cast(
120            Tag,
121            self._run(
122                self._async_tags.create(
123                    name=name,
124                    color=color,
125                    is_inbox_tag=is_inbox_tag,
126                    match=match,
127                    matching_algorithm=matching_algorithm,
128                    is_insensitive=is_insensitive,
129                    parent=parent,
130                    owner=owner,
131                    set_permissions=set_permissions,
132                )
133            ),
134        )

Create a new tag.

Arguments:
  • name: Tag name. Must be unique.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • parent: ID of parent tag for hierarchical trees.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets. Pass None to create with empty permissions.
Returns:

The newly created ~easypaperless.models.tags.Tag.

def update( self, id: int, *, name: str | easypaperless.Unset = UNSET, color: str | easypaperless.Unset = UNSET, is_inbox_tag: bool | easypaperless.Unset = UNSET, match: str | easypaperless.Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | easypaperless.Unset = UNSET, is_insensitive: bool | easypaperless.Unset = UNSET, parent: int | None | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless.Unset = UNSET) -> easypaperless.Tag:
136    def update(
137        self,
138        id: int,
139        *,
140        name: str | Unset = UNSET,
141        color: str | Unset = UNSET,
142        is_inbox_tag: bool | Unset = UNSET,
143        match: str | Unset = UNSET,
144        matching_algorithm: MatchingAlgorithm | Unset = UNSET,
145        is_insensitive: bool | Unset = UNSET,
146        parent: int | None | Unset = UNSET,
147        owner: int | None | Unset = UNSET,
148        set_permissions: SetPermissions | None | Unset = UNSET,
149    ) -> Tag:
150        """Partially update a tag (PATCH semantics).
151
152        Args:
153            id: Numeric ID of the tag to update.
154            name: Tag name.
155            color: Background colour as a CSS hex string.
156            is_inbox_tag: When ``True``, newly ingested documents get this tag.
157            match: Auto-matching pattern.
158            matching_algorithm: Controls how ``match`` is applied.
159                E.g. ``matching_algorithm=MatchingAlgorithm.REGEX`` for
160                regular-expression matching.
161            is_insensitive: When ``True``, ``match`` is case-insensitive.
162            parent: ID of parent tag.
163                Pass ``None`` to clear (make root tag).
164                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
165            owner: Numeric user ID to assign as owner.
166                Pass ``None`` to clear the owner.
167                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
168            set_permissions: Explicit view/change permission sets.
169                Pass ``None`` to clear all permissions (overwrite with empty).
170                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
171
172        Returns:
173            The updated :class:`~easypaperless.models.tags.Tag`.
174        """
175        return cast(
176            Tag,
177            self._run(
178                self._async_tags.update(
179                    id,
180                    name=name,
181                    color=color,
182                    is_inbox_tag=is_inbox_tag,
183                    match=match,
184                    matching_algorithm=matching_algorithm,
185                    is_insensitive=is_insensitive,
186                    parent=parent,
187                    owner=owner,
188                    set_permissions=set_permissions,
189                )
190            ),
191        )

Partially update a tag (PATCH semantics).

Arguments:
  • id: Numeric ID of the tag to update.
  • name: Tag name.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied. E.g. matching_algorithm=MatchingAlgorithm.REGEX for regular-expression matching.
  • is_insensitive: When True, match is case-insensitive.
  • parent: ID of parent tag. Pass None to clear (make root tag). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Pass None to clear all permissions (overwrite with empty). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.tags.Tag.

def delete(self, id: int) -> None:
193    def delete(self, id: int) -> None:
194        """Delete a tag.
195
196        Args:
197            id: Numeric ID of the tag to delete.
198
199        Raises:
200            ~easypaperless.exceptions.NotFoundError: If no tag exists with
201                that ID.
202        """
203        self._run(self._async_tags.delete(id))

Delete a tag.

Arguments:
  • id: Numeric ID of the tag to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
205    def bulk_delete(self, ids: List[int]) -> None:
206        """Permanently delete multiple tags in a single request.
207
208        Args:
209            ids: List of tag IDs to delete.
210        """
211        self._run(self._async_tags.bulk_delete(ids))

Permanently delete multiple tags in a single request.

Arguments:
  • ids: List of tag IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | easypaperless.Unset = UNSET, owner: int | None | easypaperless.Unset = UNSET, merge: bool = False) -> None:
213    def bulk_set_permissions(
214        self,
215        ids: List[int],
216        *,
217        set_permissions: SetPermissions | Unset = UNSET,
218        owner: int | None | Unset = UNSET,
219        merge: bool = False,
220    ) -> None:
221        """Set permissions and/or owner on multiple tags.
222
223        Args:
224            ids: List of tag IDs to modify.
225            set_permissions: Explicit view/change permission sets.
226                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
227            owner: Numeric user ID to assign as owner.
228                Pass ``None`` to clear the owner.
229                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
230            merge: When ``True``, new permissions are merged with existing ones.
231        """
232        self._run(
233            self._async_tags.bulk_set_permissions(
234                ids, set_permissions=set_permissions, owner=owner, merge=merge
235            )
236        )

Set permissions and/or owner on multiple tags.

Arguments:
  • ids: List of tag IDs to modify.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • merge: When True, new permissions are merged with existing ones.
class UsersResource:
 20class UsersResource:
 21    """Accessor for users: ``client.users``."""
 22
 23    def __init__(self, core: _ClientCore) -> None:
 24        self._core = core
 25
 26    async def list(
 27        self,
 28        *,
 29        username_contains: str | Unset = UNSET,
 30        username_exact: str | Unset = UNSET,
 31        ordering: str | Unset = UNSET,
 32        page: int | Unset = UNSET,
 33        page_size: int | Unset = UNSET,
 34    ) -> PagedResult[User]:
 35        """Return users defined in paperless-ngx.
 36
 37        When ``page`` is ``UNSET`` (the default), all pages are fetched
 38        automatically and ``next`` / ``previous`` in the result are always
 39        ``None``.  When ``page`` is set, only that page is fetched and
 40        ``next`` / ``previous`` reflect the raw API values.
 41
 42        Args:
 43            username_contains: Case-insensitive substring filter on username.
 44            username_exact: Case-insensitive exact match on username.
 45            ordering: Field to sort by.
 46            page: Return only this specific page (1-based).
 47            page_size: Number of results per page.
 48
 49        Returns:
 50            :class:`~easypaperless.models.paged_result.PagedResult` of
 51            :class:`~easypaperless.models.users.User` objects.
 52        """
 53        logger.info("Listing users")
 54        params: dict[str, Any] = {}
 55        if not isinstance(username_contains, Unset):
 56            params["username__icontains"] = username_contains
 57        if not isinstance(username_exact, Unset):
 58            params["username__iexact"] = username_exact
 59        if not isinstance(ordering, Unset):
 60            params["ordering"] = ordering
 61        if not isinstance(page, Unset):
 62            params["page"] = page
 63        if not isinstance(page_size, Unset):
 64            params["page_size"] = page_size
 65        return cast(
 66            PagedResult[User],
 67            await self._core._list_resource("users", User, params or None),
 68        )
 69
 70    async def get(self, id: int) -> User:
 71        """Fetch a single user by their ID.
 72
 73        Args:
 74            id: Numeric user ID.
 75
 76        Returns:
 77            The :class:`~easypaperless.models.users.User` with the given ID.
 78
 79        Raises:
 80            ~easypaperless.exceptions.NotFoundError: If no user exists with
 81                that ID.
 82        """
 83        logger.info("Getting user id=%d", id)
 84        return cast(User, await self._core._get_resource("users", id, User))
 85
 86    async def create(
 87        self,
 88        *,
 89        username: str,
 90        email: str | Unset = UNSET,
 91        password: str | Unset = UNSET,
 92        first_name: str | Unset = UNSET,
 93        last_name: str | Unset = UNSET,
 94        date_joined: datetime | Unset = UNSET,
 95        is_staff: bool | Unset = UNSET,
 96        is_active: bool | Unset = UNSET,
 97        is_superuser: bool | Unset = UNSET,
 98        groups: List[int] | Unset = UNSET,
 99        user_permissions: List[str] | Unset = UNSET,
100    ) -> User:
101        """Create a new user.
102
103        Args:
104            username: Login username. Must be unique.
105            email: Email address.
106            password: Password for the new account.
107            first_name: Given name.
108            last_name: Family name.
109            date_joined: Account creation timestamp.
110            is_staff: Grant staff (admin UI) access.
111            is_active: Whether the account is active.
112            is_superuser: Grant unrestricted superuser access.
113            groups: IDs of groups to assign the user to.
114            user_permissions: Directly assigned permission strings.
115
116        Returns:
117            The newly created :class:`~easypaperless.models.users.User`.
118        """
119        logger.info("Creating user username=%r", username)
120        return cast(
121            User,
122            await self._core._create_resource(
123                "users",
124                User,
125                username=username,
126                email=email,
127                password=password,
128                first_name=first_name,
129                last_name=last_name,
130                date_joined=date_joined,
131                is_staff=is_staff,
132                is_active=is_active,
133                is_superuser=is_superuser,
134                groups=groups,
135                user_permissions=user_permissions,
136            ),
137        )
138
139    async def update(
140        self,
141        id: int,
142        *,
143        username: str | Unset = UNSET,
144        email: str | Unset = UNSET,
145        password: str | Unset = UNSET,
146        first_name: str | Unset = UNSET,
147        last_name: str | Unset = UNSET,
148        date_joined: datetime | Unset = UNSET,
149        is_staff: bool | Unset = UNSET,
150        is_active: bool | Unset = UNSET,
151        is_superuser: bool | Unset = UNSET,
152        groups: List[int] | Unset = UNSET,
153        user_permissions: List[str] | Unset = UNSET,
154    ) -> User:
155        """Partially update a user (PATCH semantics).
156
157        Only fields with a non-:data:`~easypaperless.UNSET` value are included
158        in the request body.  Omit a parameter (or pass
159        :data:`~easypaperless.UNSET`) to leave it unchanged.
160
161        Args:
162            id: Numeric ID of the user to update.
163            username: Login username.
164            email: Email address.
165            password: New password.
166            first_name: Given name.
167            last_name: Family name.
168            date_joined: Account creation timestamp.
169            is_staff: Grant or revoke staff access.
170            is_active: Activate or deactivate the account.
171            is_superuser: Grant or revoke superuser access.
172            groups: IDs of groups to assign the user to.
173            user_permissions: Directly assigned permission strings.
174
175        Returns:
176            The updated :class:`~easypaperless.models.users.User`.
177        """
178        logger.info("Updating user id=%d", id)
179        return cast(
180            User,
181            await self._core._update_resource(
182                "users",
183                id,
184                User,
185                username=username,
186                email=email,
187                password=password,
188                first_name=first_name,
189                last_name=last_name,
190                date_joined=date_joined,
191                is_staff=is_staff,
192                is_active=is_active,
193                is_superuser=is_superuser,
194                groups=groups,
195                user_permissions=user_permissions,
196            ),
197        )
198
199    async def delete(self, id: int) -> None:
200        """Delete a user.
201
202        Args:
203            id: Numeric ID of the user to delete.
204
205        Raises:
206            ~easypaperless.exceptions.NotFoundError: If no user exists with
207                that ID.
208        """
209        logger.info("Deleting user id=%d", id)
210        await self._core._delete_resource("users", id)

Accessor for users: client.users.

UsersResource(core: easypaperless.client._ClientCore)
23    def __init__(self, core: _ClientCore) -> None:
24        self._core = core
async def list( self, *, username_contains: str | easypaperless.Unset = UNSET, username_exact: str | easypaperless.Unset = UNSET, ordering: str | easypaperless.Unset = UNSET, page: int | easypaperless.Unset = UNSET, page_size: int | easypaperless.Unset = UNSET) -> easypaperless.PagedResult[User]:
26    async def list(
27        self,
28        *,
29        username_contains: str | Unset = UNSET,
30        username_exact: str | Unset = UNSET,
31        ordering: str | Unset = UNSET,
32        page: int | Unset = UNSET,
33        page_size: int | Unset = UNSET,
34    ) -> PagedResult[User]:
35        """Return users defined in paperless-ngx.
36
37        When ``page`` is ``UNSET`` (the default), all pages are fetched
38        automatically and ``next`` / ``previous`` in the result are always
39        ``None``.  When ``page`` is set, only that page is fetched and
40        ``next`` / ``previous`` reflect the raw API values.
41
42        Args:
43            username_contains: Case-insensitive substring filter on username.
44            username_exact: Case-insensitive exact match on username.
45            ordering: Field to sort by.
46            page: Return only this specific page (1-based).
47            page_size: Number of results per page.
48
49        Returns:
50            :class:`~easypaperless.models.paged_result.PagedResult` of
51            :class:`~easypaperless.models.users.User` objects.
52        """
53        logger.info("Listing users")
54        params: dict[str, Any] = {}
55        if not isinstance(username_contains, Unset):
56            params["username__icontains"] = username_contains
57        if not isinstance(username_exact, Unset):
58            params["username__iexact"] = username_exact
59        if not isinstance(ordering, Unset):
60            params["ordering"] = ordering
61        if not isinstance(page, Unset):
62            params["page"] = page
63        if not isinstance(page_size, Unset):
64            params["page_size"] = page_size
65        return cast(
66            PagedResult[User],
67            await self._core._list_resource("users", User, params or None),
68        )

Return users defined in paperless-ngx.

When page is UNSET (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • username_contains: Case-insensitive substring filter on username.
  • username_exact: Case-insensitive exact match on username.
  • ordering: Field to sort by.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.users.User objects.

async def get(self, id: int) -> easypaperless.User:
70    async def get(self, id: int) -> User:
71        """Fetch a single user by their ID.
72
73        Args:
74            id: Numeric user ID.
75
76        Returns:
77            The :class:`~easypaperless.models.users.User` with the given ID.
78
79        Raises:
80            ~easypaperless.exceptions.NotFoundError: If no user exists with
81                that ID.
82        """
83        logger.info("Getting user id=%d", id)
84        return cast(User, await self._core._get_resource("users", id, User))

Fetch a single user by their ID.

Arguments:
  • id: Numeric user ID.
Returns:

The ~easypaperless.models.users.User with the given ID.

Raises:
async def create( self, *, username: str, email: str | easypaperless.Unset = UNSET, password: str | easypaperless.Unset = UNSET, first_name: str | easypaperless.Unset = UNSET, last_name: str | easypaperless.Unset = UNSET, date_joined: datetime.datetime | easypaperless.Unset = UNSET, is_staff: bool | easypaperless.Unset = UNSET, is_active: bool | easypaperless.Unset = UNSET, is_superuser: bool | easypaperless.Unset = UNSET, groups: Union[List[int], easypaperless.Unset] = UNSET, user_permissions: Union[List[str], easypaperless.Unset] = UNSET) -> easypaperless.User:
 86    async def create(
 87        self,
 88        *,
 89        username: str,
 90        email: str | Unset = UNSET,
 91        password: str | Unset = UNSET,
 92        first_name: str | Unset = UNSET,
 93        last_name: str | Unset = UNSET,
 94        date_joined: datetime | Unset = UNSET,
 95        is_staff: bool | Unset = UNSET,
 96        is_active: bool | Unset = UNSET,
 97        is_superuser: bool | Unset = UNSET,
 98        groups: List[int] | Unset = UNSET,
 99        user_permissions: List[str] | Unset = UNSET,
100    ) -> User:
101        """Create a new user.
102
103        Args:
104            username: Login username. Must be unique.
105            email: Email address.
106            password: Password for the new account.
107            first_name: Given name.
108            last_name: Family name.
109            date_joined: Account creation timestamp.
110            is_staff: Grant staff (admin UI) access.
111            is_active: Whether the account is active.
112            is_superuser: Grant unrestricted superuser access.
113            groups: IDs of groups to assign the user to.
114            user_permissions: Directly assigned permission strings.
115
116        Returns:
117            The newly created :class:`~easypaperless.models.users.User`.
118        """
119        logger.info("Creating user username=%r", username)
120        return cast(
121            User,
122            await self._core._create_resource(
123                "users",
124                User,
125                username=username,
126                email=email,
127                password=password,
128                first_name=first_name,
129                last_name=last_name,
130                date_joined=date_joined,
131                is_staff=is_staff,
132                is_active=is_active,
133                is_superuser=is_superuser,
134                groups=groups,
135                user_permissions=user_permissions,
136            ),
137        )

Create a new user.

Arguments:
  • username: Login username. Must be unique.
  • email: Email address.
  • password: Password for the new account.
  • first_name: Given name.
  • last_name: Family name.
  • date_joined: Account creation timestamp.
  • is_staff: Grant staff (admin UI) access.
  • is_active: Whether the account is active.
  • is_superuser: Grant unrestricted superuser access.
  • groups: IDs of groups to assign the user to.
  • user_permissions: Directly assigned permission strings.
Returns:

The newly created ~easypaperless.models.users.User.

async def update( self, id: int, *, username: str | easypaperless.Unset = UNSET, email: str | easypaperless.Unset = UNSET, password: str | easypaperless.Unset = UNSET, first_name: str | easypaperless.Unset = UNSET, last_name: str | easypaperless.Unset = UNSET, date_joined: datetime.datetime | easypaperless.Unset = UNSET, is_staff: bool | easypaperless.Unset = UNSET, is_active: bool | easypaperless.Unset = UNSET, is_superuser: bool | easypaperless.Unset = UNSET, groups: Union[List[int], easypaperless.Unset] = UNSET, user_permissions: Union[List[str], easypaperless.Unset] = UNSET) -> easypaperless.User:
139    async def update(
140        self,
141        id: int,
142        *,
143        username: str | Unset = UNSET,
144        email: str | Unset = UNSET,
145        password: str | Unset = UNSET,
146        first_name: str | Unset = UNSET,
147        last_name: str | Unset = UNSET,
148        date_joined: datetime | Unset = UNSET,
149        is_staff: bool | Unset = UNSET,
150        is_active: bool | Unset = UNSET,
151        is_superuser: bool | Unset = UNSET,
152        groups: List[int] | Unset = UNSET,
153        user_permissions: List[str] | Unset = UNSET,
154    ) -> User:
155        """Partially update a user (PATCH semantics).
156
157        Only fields with a non-:data:`~easypaperless.UNSET` value are included
158        in the request body.  Omit a parameter (or pass
159        :data:`~easypaperless.UNSET`) to leave it unchanged.
160
161        Args:
162            id: Numeric ID of the user to update.
163            username: Login username.
164            email: Email address.
165            password: New password.
166            first_name: Given name.
167            last_name: Family name.
168            date_joined: Account creation timestamp.
169            is_staff: Grant or revoke staff access.
170            is_active: Activate or deactivate the account.
171            is_superuser: Grant or revoke superuser access.
172            groups: IDs of groups to assign the user to.
173            user_permissions: Directly assigned permission strings.
174
175        Returns:
176            The updated :class:`~easypaperless.models.users.User`.
177        """
178        logger.info("Updating user id=%d", id)
179        return cast(
180            User,
181            await self._core._update_resource(
182                "users",
183                id,
184                User,
185                username=username,
186                email=email,
187                password=password,
188                first_name=first_name,
189                last_name=last_name,
190                date_joined=date_joined,
191                is_staff=is_staff,
192                is_active=is_active,
193                is_superuser=is_superuser,
194                groups=groups,
195                user_permissions=user_permissions,
196            ),
197        )

Partially update a user (PATCH semantics).

Only fields with a non-~easypaperless.UNSET value are included in the request body. Omit a parameter (or pass ~easypaperless.UNSET) to leave it unchanged.

Arguments:
  • id: Numeric ID of the user to update.
  • username: Login username.
  • email: Email address.
  • password: New password.
  • first_name: Given name.
  • last_name: Family name.
  • date_joined: Account creation timestamp.
  • is_staff: Grant or revoke staff access.
  • is_active: Activate or deactivate the account.
  • is_superuser: Grant or revoke superuser access.
  • groups: IDs of groups to assign the user to.
  • user_permissions: Directly assigned permission strings.
Returns:

The updated ~easypaperless.models.users.User.

async def delete(self, id: int) -> None:
199    async def delete(self, id: int) -> None:
200        """Delete a user.
201
202        Args:
203            id: Numeric ID of the user to delete.
204
205        Raises:
206            ~easypaperless.exceptions.NotFoundError: If no user exists with
207                that ID.
208        """
209        logger.info("Deleting user id=%d", id)
210        await self._core._delete_resource("users", id)

Delete a user.

Arguments:
  • id: Numeric ID of the user to delete.
Raises:
class SyncUsersResource:
 17class SyncUsersResource:
 18    """Sync accessor for users: ``client.users``."""
 19
 20    def __init__(self, async_users: UsersResource, run: Any) -> None:
 21        self._async_users = async_users
 22        self._run = run
 23
 24    def list(
 25        self,
 26        *,
 27        username_contains: str | Unset = UNSET,
 28        username_exact: str | Unset = UNSET,
 29        ordering: str | Unset = UNSET,
 30        page: int | Unset = UNSET,
 31        page_size: int | Unset = UNSET,
 32    ) -> PagedResult[User]:
 33        """Return users defined in paperless-ngx.
 34
 35        When ``page`` is ``UNSET`` (the default), all pages are fetched
 36        automatically and ``next`` / ``previous`` in the result are always
 37        ``None``.  When ``page`` is set, only that page is fetched and
 38        ``next`` / ``previous`` reflect the raw API values.
 39
 40        Args:
 41            username_contains: Case-insensitive substring filter on username.
 42            username_exact: Case-insensitive exact match on username.
 43            ordering: Field to sort by.
 44            page: Return only this specific page (1-based).
 45            page_size: Number of results per page.
 46
 47        Returns:
 48            :class:`~easypaperless.models.paged_result.PagedResult` of
 49            :class:`~easypaperless.models.users.User` objects.
 50        """
 51        return cast(
 52            PagedResult[User],
 53            self._run(
 54                self._async_users.list(
 55                    username_contains=username_contains,
 56                    username_exact=username_exact,
 57                    ordering=ordering,
 58                    page=page,
 59                    page_size=page_size,
 60                )
 61            ),
 62        )
 63
 64    def get(self, id: int) -> User:
 65        """Fetch a single user by their ID.
 66
 67        Args:
 68            id: Numeric user ID.
 69
 70        Returns:
 71            The :class:`~easypaperless.models.users.User` with the given ID.
 72
 73        Raises:
 74            ~easypaperless.exceptions.NotFoundError: If no user exists with
 75                that ID.
 76        """
 77        return cast(User, self._run(self._async_users.get(id)))
 78
 79    def create(
 80        self,
 81        *,
 82        username: str,
 83        email: str | Unset = UNSET,
 84        password: str | Unset = UNSET,
 85        first_name: str | Unset = UNSET,
 86        last_name: str | Unset = UNSET,
 87        date_joined: datetime | Unset = UNSET,
 88        is_staff: bool | Unset = UNSET,
 89        is_active: bool | Unset = UNSET,
 90        is_superuser: bool | Unset = UNSET,
 91        groups: List[int] | Unset = UNSET,
 92        user_permissions: List[str] | Unset = UNSET,
 93    ) -> User:
 94        """Create a new user.
 95
 96        Args:
 97            username: Login username. Must be unique.
 98            email: Email address.
 99            password: Password for the new account.
100            first_name: Given name.
101            last_name: Family name.
102            date_joined: Account creation timestamp.
103            is_staff: Grant staff (admin UI) access.
104            is_active: Whether the account is active.
105            is_superuser: Grant unrestricted superuser access.
106            groups: IDs of groups to assign the user to.
107            user_permissions: Directly assigned permission strings.
108
109        Returns:
110            The newly created :class:`~easypaperless.models.users.User`.
111        """
112        return cast(
113            User,
114            self._run(
115                self._async_users.create(
116                    username=username,
117                    email=email,
118                    password=password,
119                    first_name=first_name,
120                    last_name=last_name,
121                    date_joined=date_joined,
122                    is_staff=is_staff,
123                    is_active=is_active,
124                    is_superuser=is_superuser,
125                    groups=groups,
126                    user_permissions=user_permissions,
127                )
128            ),
129        )
130
131    def update(
132        self,
133        id: int,
134        *,
135        username: str | Unset = UNSET,
136        email: str | Unset = UNSET,
137        password: str | Unset = UNSET,
138        first_name: str | Unset = UNSET,
139        last_name: str | Unset = UNSET,
140        date_joined: datetime | Unset = UNSET,
141        is_staff: bool | Unset = UNSET,
142        is_active: bool | Unset = UNSET,
143        is_superuser: bool | Unset = UNSET,
144        groups: List[int] | Unset = UNSET,
145        user_permissions: List[str] | Unset = UNSET,
146    ) -> User:
147        """Partially update a user (PATCH semantics).
148
149        Only fields with a non-:data:`~easypaperless.UNSET` value are included
150        in the request body.  Omit a parameter (or pass
151        :data:`~easypaperless.UNSET`) to leave it unchanged.
152
153        Args:
154            id: Numeric ID of the user to update.
155            username: Login username.
156            email: Email address.
157            password: New password.
158            first_name: Given name.
159            last_name: Family name.
160            date_joined: Account creation timestamp.
161            is_staff: Grant or revoke staff access.
162            is_active: Activate or deactivate the account.
163            is_superuser: Grant or revoke superuser access.
164            groups: IDs of groups to assign the user to.
165            user_permissions: Directly assigned permission strings.
166
167        Returns:
168            The updated :class:`~easypaperless.models.users.User`.
169        """
170        return cast(
171            User,
172            self._run(
173                self._async_users.update(
174                    id,
175                    username=username,
176                    email=email,
177                    password=password,
178                    first_name=first_name,
179                    last_name=last_name,
180                    date_joined=date_joined,
181                    is_staff=is_staff,
182                    is_active=is_active,
183                    is_superuser=is_superuser,
184                    groups=groups,
185                    user_permissions=user_permissions,
186                )
187            ),
188        )
189
190    def delete(self, id: int) -> None:
191        """Delete a user.
192
193        Args:
194            id: Numeric ID of the user to delete.
195
196        Raises:
197            ~easypaperless.exceptions.NotFoundError: If no user exists with
198                that ID.
199        """
200        self._run(self._async_users.delete(id))

Sync accessor for users: client.users.

SyncUsersResource( async_users: UsersResource, run: Any)
20    def __init__(self, async_users: UsersResource, run: Any) -> None:
21        self._async_users = async_users
22        self._run = run
def list( self, *, username_contains: str | easypaperless.Unset = UNSET, username_exact: str | easypaperless.Unset = UNSET, ordering: str | easypaperless.Unset = UNSET, page: int | easypaperless.Unset = UNSET, page_size: int | easypaperless.Unset = UNSET) -> easypaperless.PagedResult[User]:
24    def list(
25        self,
26        *,
27        username_contains: str | Unset = UNSET,
28        username_exact: str | Unset = UNSET,
29        ordering: str | Unset = UNSET,
30        page: int | Unset = UNSET,
31        page_size: int | Unset = UNSET,
32    ) -> PagedResult[User]:
33        """Return users defined in paperless-ngx.
34
35        When ``page`` is ``UNSET`` (the default), all pages are fetched
36        automatically and ``next`` / ``previous`` in the result are always
37        ``None``.  When ``page`` is set, only that page is fetched and
38        ``next`` / ``previous`` reflect the raw API values.
39
40        Args:
41            username_contains: Case-insensitive substring filter on username.
42            username_exact: Case-insensitive exact match on username.
43            ordering: Field to sort by.
44            page: Return only this specific page (1-based).
45            page_size: Number of results per page.
46
47        Returns:
48            :class:`~easypaperless.models.paged_result.PagedResult` of
49            :class:`~easypaperless.models.users.User` objects.
50        """
51        return cast(
52            PagedResult[User],
53            self._run(
54                self._async_users.list(
55                    username_contains=username_contains,
56                    username_exact=username_exact,
57                    ordering=ordering,
58                    page=page,
59                    page_size=page_size,
60                )
61            ),
62        )

Return users defined in paperless-ngx.

When page is UNSET (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • username_contains: Case-insensitive substring filter on username.
  • username_exact: Case-insensitive exact match on username.
  • ordering: Field to sort by.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.users.User objects.

def get(self, id: int) -> easypaperless.User:
64    def get(self, id: int) -> User:
65        """Fetch a single user by their ID.
66
67        Args:
68            id: Numeric user ID.
69
70        Returns:
71            The :class:`~easypaperless.models.users.User` with the given ID.
72
73        Raises:
74            ~easypaperless.exceptions.NotFoundError: If no user exists with
75                that ID.
76        """
77        return cast(User, self._run(self._async_users.get(id)))

Fetch a single user by their ID.

Arguments:
  • id: Numeric user ID.
Returns:

The ~easypaperless.models.users.User with the given ID.

Raises:
def create( self, *, username: str, email: str | easypaperless.Unset = UNSET, password: str | easypaperless.Unset = UNSET, first_name: str | easypaperless.Unset = UNSET, last_name: str | easypaperless.Unset = UNSET, date_joined: datetime.datetime | easypaperless.Unset = UNSET, is_staff: bool | easypaperless.Unset = UNSET, is_active: bool | easypaperless.Unset = UNSET, is_superuser: bool | easypaperless.Unset = UNSET, groups: Union[List[int], easypaperless.Unset] = UNSET, user_permissions: Union[List[str], easypaperless.Unset] = UNSET) -> easypaperless.User:
 79    def create(
 80        self,
 81        *,
 82        username: str,
 83        email: str | Unset = UNSET,
 84        password: str | Unset = UNSET,
 85        first_name: str | Unset = UNSET,
 86        last_name: str | Unset = UNSET,
 87        date_joined: datetime | Unset = UNSET,
 88        is_staff: bool | Unset = UNSET,
 89        is_active: bool | Unset = UNSET,
 90        is_superuser: bool | Unset = UNSET,
 91        groups: List[int] | Unset = UNSET,
 92        user_permissions: List[str] | Unset = UNSET,
 93    ) -> User:
 94        """Create a new user.
 95
 96        Args:
 97            username: Login username. Must be unique.
 98            email: Email address.
 99            password: Password for the new account.
100            first_name: Given name.
101            last_name: Family name.
102            date_joined: Account creation timestamp.
103            is_staff: Grant staff (admin UI) access.
104            is_active: Whether the account is active.
105            is_superuser: Grant unrestricted superuser access.
106            groups: IDs of groups to assign the user to.
107            user_permissions: Directly assigned permission strings.
108
109        Returns:
110            The newly created :class:`~easypaperless.models.users.User`.
111        """
112        return cast(
113            User,
114            self._run(
115                self._async_users.create(
116                    username=username,
117                    email=email,
118                    password=password,
119                    first_name=first_name,
120                    last_name=last_name,
121                    date_joined=date_joined,
122                    is_staff=is_staff,
123                    is_active=is_active,
124                    is_superuser=is_superuser,
125                    groups=groups,
126                    user_permissions=user_permissions,
127                )
128            ),
129        )

Create a new user.

Arguments:
  • username: Login username. Must be unique.
  • email: Email address.
  • password: Password for the new account.
  • first_name: Given name.
  • last_name: Family name.
  • date_joined: Account creation timestamp.
  • is_staff: Grant staff (admin UI) access.
  • is_active: Whether the account is active.
  • is_superuser: Grant unrestricted superuser access.
  • groups: IDs of groups to assign the user to.
  • user_permissions: Directly assigned permission strings.
Returns:

The newly created ~easypaperless.models.users.User.

def update( self, id: int, *, username: str | easypaperless.Unset = UNSET, email: str | easypaperless.Unset = UNSET, password: str | easypaperless.Unset = UNSET, first_name: str | easypaperless.Unset = UNSET, last_name: str | easypaperless.Unset = UNSET, date_joined: datetime.datetime | easypaperless.Unset = UNSET, is_staff: bool | easypaperless.Unset = UNSET, is_active: bool | easypaperless.Unset = UNSET, is_superuser: bool | easypaperless.Unset = UNSET, groups: Union[List[int], easypaperless.Unset] = UNSET, user_permissions: Union[List[str], easypaperless.Unset] = UNSET) -> easypaperless.User:
131    def update(
132        self,
133        id: int,
134        *,
135        username: str | Unset = UNSET,
136        email: str | Unset = UNSET,
137        password: str | Unset = UNSET,
138        first_name: str | Unset = UNSET,
139        last_name: str | Unset = UNSET,
140        date_joined: datetime | Unset = UNSET,
141        is_staff: bool | Unset = UNSET,
142        is_active: bool | Unset = UNSET,
143        is_superuser: bool | Unset = UNSET,
144        groups: List[int] | Unset = UNSET,
145        user_permissions: List[str] | Unset = UNSET,
146    ) -> User:
147        """Partially update a user (PATCH semantics).
148
149        Only fields with a non-:data:`~easypaperless.UNSET` value are included
150        in the request body.  Omit a parameter (or pass
151        :data:`~easypaperless.UNSET`) to leave it unchanged.
152
153        Args:
154            id: Numeric ID of the user to update.
155            username: Login username.
156            email: Email address.
157            password: New password.
158            first_name: Given name.
159            last_name: Family name.
160            date_joined: Account creation timestamp.
161            is_staff: Grant or revoke staff access.
162            is_active: Activate or deactivate the account.
163            is_superuser: Grant or revoke superuser access.
164            groups: IDs of groups to assign the user to.
165            user_permissions: Directly assigned permission strings.
166
167        Returns:
168            The updated :class:`~easypaperless.models.users.User`.
169        """
170        return cast(
171            User,
172            self._run(
173                self._async_users.update(
174                    id,
175                    username=username,
176                    email=email,
177                    password=password,
178                    first_name=first_name,
179                    last_name=last_name,
180                    date_joined=date_joined,
181                    is_staff=is_staff,
182                    is_active=is_active,
183                    is_superuser=is_superuser,
184                    groups=groups,
185                    user_permissions=user_permissions,
186                )
187            ),
188        )

Partially update a user (PATCH semantics).

Only fields with a non-~easypaperless.UNSET value are included in the request body. Omit a parameter (or pass ~easypaperless.UNSET) to leave it unchanged.

Arguments:
  • id: Numeric ID of the user to update.
  • username: Login username.
  • email: Email address.
  • password: New password.
  • first_name: Given name.
  • last_name: Family name.
  • date_joined: Account creation timestamp.
  • is_staff: Grant or revoke staff access.
  • is_active: Activate or deactivate the account.
  • is_superuser: Grant or revoke superuser access.
  • groups: IDs of groups to assign the user to.
  • user_permissions: Directly assigned permission strings.
Returns:

The updated ~easypaperless.models.users.User.

def delete(self, id: int) -> None:
190    def delete(self, id: int) -> None:
191        """Delete a user.
192
193        Args:
194            id: Numeric ID of the user to delete.
195
196        Raises:
197            ~easypaperless.exceptions.NotFoundError: If no user exists with
198                that ID.
199        """
200        self._run(self._async_users.delete(id))

Delete a user.

Arguments:
  • id: Numeric ID of the user to delete.
Raises:
class TrashResource:
19class TrashResource:
20    """Accessor for the trash bin: ``client.trash``."""
21
22    def __init__(self, core: _ClientCore) -> None:
23        self._core = core
24
25    async def list(
26        self,
27        *,
28        page: int | Unset = UNSET,
29        page_size: int | Unset = UNSET,
30    ) -> PagedResult[Document]:
31        """Return all documents currently in the trash.
32
33        When ``page`` is ``UNSET`` (the default), all pages are fetched
34        automatically and ``next`` / ``previous`` in the result are always
35        ``None``.  When ``page`` is set, only that page is fetched and
36        ``next`` / ``previous`` reflect the raw API values.
37
38        Args:
39            page: Return only this specific page (1-based).
40            page_size: Number of results per page.
41
42        Returns:
43            :class:`~easypaperless.models.paged_result.PagedResult` of
44            :class:`~easypaperless.models.documents.Document` objects currently
45            in the trash.
46        """
47        logger.info("Listing trashed documents")
48        params: dict[str, Any] = {}
49        if not isinstance(page, Unset):
50            params["page"] = page
51        if not isinstance(page_size, Unset):
52            params["page_size"] = page_size
53        return cast(
54            PagedResult[Document],
55            await self._core._list_resource("trash", Document, params or None),
56        )
57
58    async def restore(self, document_ids: List[int]) -> None:
59        """Restore trashed documents back to active status.
60
61        Args:
62            document_ids: List of numeric document IDs to restore.
63        """
64        logger.info("Restoring %d trashed document(s)", len(document_ids))
65        await self._core._session.post(
66            "/trash/",
67            json={"documents": document_ids, "action": "restore"},
68        )
69
70    async def empty(self, document_ids: List[int]) -> None:
71        """Permanently delete trashed documents.
72
73        .. warning::
74            **This operation is irreversible and cannot be undone.**
75            The documents will be permanently removed and cannot be recovered.
76
77        Args:
78            document_ids: List of numeric document IDs to permanently delete.
79        """
80        logger.info("Permanently deleting %d trashed document(s)", len(document_ids))
81        await self._core._session.post(
82            "/trash/",
83            json={"documents": document_ids, "action": "empty"},
84        )

Accessor for the trash bin: client.trash.

TrashResource(core: easypaperless.client._ClientCore)
22    def __init__(self, core: _ClientCore) -> None:
23        self._core = core
async def list( self, *, page: int | easypaperless.Unset = UNSET, page_size: int | easypaperless.Unset = UNSET) -> easypaperless.PagedResult[Document]:
25    async def list(
26        self,
27        *,
28        page: int | Unset = UNSET,
29        page_size: int | Unset = UNSET,
30    ) -> PagedResult[Document]:
31        """Return all documents currently in the trash.
32
33        When ``page`` is ``UNSET`` (the default), all pages are fetched
34        automatically and ``next`` / ``previous`` in the result are always
35        ``None``.  When ``page`` is set, only that page is fetched and
36        ``next`` / ``previous`` reflect the raw API values.
37
38        Args:
39            page: Return only this specific page (1-based).
40            page_size: Number of results per page.
41
42        Returns:
43            :class:`~easypaperless.models.paged_result.PagedResult` of
44            :class:`~easypaperless.models.documents.Document` objects currently
45            in the trash.
46        """
47        logger.info("Listing trashed documents")
48        params: dict[str, Any] = {}
49        if not isinstance(page, Unset):
50            params["page"] = page
51        if not isinstance(page_size, Unset):
52            params["page_size"] = page_size
53        return cast(
54            PagedResult[Document],
55            await self._core._list_resource("trash", Document, params or None),
56        )

Return all documents currently in the trash.

When page is UNSET (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.Document objects currently in the trash.

async def restore(self, document_ids: List[int]) -> None:
58    async def restore(self, document_ids: List[int]) -> None:
59        """Restore trashed documents back to active status.
60
61        Args:
62            document_ids: List of numeric document IDs to restore.
63        """
64        logger.info("Restoring %d trashed document(s)", len(document_ids))
65        await self._core._session.post(
66            "/trash/",
67            json={"documents": document_ids, "action": "restore"},
68        )

Restore trashed documents back to active status.

Arguments:
  • document_ids: List of numeric document IDs to restore.
async def empty(self, document_ids: List[int]) -> None:
70    async def empty(self, document_ids: List[int]) -> None:
71        """Permanently delete trashed documents.
72
73        .. warning::
74            **This operation is irreversible and cannot be undone.**
75            The documents will be permanently removed and cannot be recovered.
76
77        Args:
78            document_ids: List of numeric document IDs to permanently delete.
79        """
80        logger.info("Permanently deleting %d trashed document(s)", len(document_ids))
81        await self._core._session.post(
82            "/trash/",
83            json={"documents": document_ids, "action": "empty"},
84        )

Permanently delete trashed documents.

This operation is irreversible and cannot be undone. The documents will be permanently removed and cannot be recovered.

Arguments:
  • document_ids: List of numeric document IDs to permanently delete.
class SyncTrashResource:
16class SyncTrashResource:
17    """Sync accessor for the trash bin: ``client.trash``."""
18
19    def __init__(self, async_trash: TrashResource, run: Any) -> None:
20        self._async_trash = async_trash
21        self._run = run
22
23    def list(
24        self,
25        *,
26        page: int | Unset = UNSET,
27        page_size: int | Unset = UNSET,
28    ) -> PagedResult[Document]:
29        """Return all documents currently in the trash.
30
31        When ``page`` is ``UNSET`` (the default), all pages are fetched
32        automatically and ``next`` / ``previous`` in the result are always
33        ``None``.  When ``page`` is set, only that page is fetched and
34        ``next`` / ``previous`` reflect the raw API values.
35
36        Args:
37            page: Return only this specific page (1-based).
38            page_size: Number of results per page.
39
40        Returns:
41            :class:`~easypaperless.models.paged_result.PagedResult` of
42            :class:`~easypaperless.models.documents.Document` objects currently
43            in the trash.
44        """
45        return cast(
46            PagedResult[Document],
47            self._run(self._async_trash.list(page=page, page_size=page_size)),
48        )
49
50    def restore(self, document_ids: List[int]) -> None:
51        """Restore trashed documents back to active status.
52
53        Args:
54            document_ids: List of numeric document IDs to restore.
55        """
56        self._run(self._async_trash.restore(document_ids))
57
58    def empty(self, document_ids: List[int]) -> None:
59        """Permanently delete trashed documents.
60
61        .. warning::
62            **This operation is irreversible and cannot be undone.**
63            The documents will be permanently removed and cannot be recovered.
64
65        Args:
66            document_ids: List of numeric document IDs to permanently delete.
67        """
68        self._run(self._async_trash.empty(document_ids))

Sync accessor for the trash bin: client.trash.

SyncTrashResource( async_trash: TrashResource, run: Any)
19    def __init__(self, async_trash: TrashResource, run: Any) -> None:
20        self._async_trash = async_trash
21        self._run = run
def list( self, *, page: int | easypaperless.Unset = UNSET, page_size: int | easypaperless.Unset = UNSET) -> easypaperless.PagedResult[Document]:
23    def list(
24        self,
25        *,
26        page: int | Unset = UNSET,
27        page_size: int | Unset = UNSET,
28    ) -> PagedResult[Document]:
29        """Return all documents currently in the trash.
30
31        When ``page`` is ``UNSET`` (the default), all pages are fetched
32        automatically and ``next`` / ``previous`` in the result are always
33        ``None``.  When ``page`` is set, only that page is fetched and
34        ``next`` / ``previous`` reflect the raw API values.
35
36        Args:
37            page: Return only this specific page (1-based).
38            page_size: Number of results per page.
39
40        Returns:
41            :class:`~easypaperless.models.paged_result.PagedResult` of
42            :class:`~easypaperless.models.documents.Document` objects currently
43            in the trash.
44        """
45        return cast(
46            PagedResult[Document],
47            self._run(self._async_trash.list(page=page, page_size=page_size)),
48        )

Return all documents currently in the trash.

When page is UNSET (the default), all pages are fetched automatically and next / previous in the result are always None. When page is set, only that page is fetched and next / previous reflect the raw API values.

Arguments:
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
Returns:

~easypaperless.models.paged_result.PagedResult of ~easypaperless.models.documents.Document objects currently in the trash.

def restore(self, document_ids: List[int]) -> None:
50    def restore(self, document_ids: List[int]) -> None:
51        """Restore trashed documents back to active status.
52
53        Args:
54            document_ids: List of numeric document IDs to restore.
55        """
56        self._run(self._async_trash.restore(document_ids))

Restore trashed documents back to active status.

Arguments:
  • document_ids: List of numeric document IDs to restore.
def empty(self, document_ids: List[int]) -> None:
58    def empty(self, document_ids: List[int]) -> None:
59        """Permanently delete trashed documents.
60
61        .. warning::
62            **This operation is irreversible and cannot be undone.**
63            The documents will be permanently removed and cannot be recovered.
64
65        Args:
66            document_ids: List of numeric document IDs to permanently delete.
67        """
68        self._run(self._async_trash.empty(document_ids))

Permanently delete trashed documents.

This operation is irreversible and cannot be undone. The documents will be permanently removed and cannot be recovered.

Arguments:
  • document_ids: List of numeric document IDs to permanently delete.