pax_global_header 0000666 0000000 0000000 00000000064 15053074171 0014515 g ustar 00root root 0000000 0000000 52 comment=3e425469e0989aea88ec0d824988b51e9dbc55ce
paperless-api-5.1.0/ 0000775 0000000 0000000 00000000000 15053074171 0014265 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/.devcontainer/ 0000775 0000000 0000000 00000000000 15053074171 0017024 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/.devcontainer/devcontainer.json 0000664 0000000 0000000 00000004464 15053074171 0022410 0 ustar 00root root 0000000 0000000 {
"name": "pypaperless Developer",
"context": "..",
"dockerFile": "../Dockerfile.dev",
"postCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder} && script/setup",
"postStartCommand": "script/bootstrap",
"containerEnv": {
"DEVCONTAINER": "true"
},
"features": {},
"runArgs": [
"-e",
"GIT_EDITOR=code --wait",
"--security-opt",
"label=disable"
],
"customizations": {
"vscode": {
"extensions": [
"charliermarsh.ruff",
"ms-python.pylint",
"ms-python.vscode-pylance",
"redhat.vscode-yaml",
"esbenp.prettier-vscode",
"visualstudioexptteam.vscodeintellicode",
"GitHub.vscode-pull-request-github",
"ryanluker.vscode-coverage-gutters",
"yzhang.markdown-all-in-one"
],
"settings": {
"coverage-gutters.customizable.context-menu": true,
"coverage-gutters.customizable.status-bar-toggler-watchCoverageAndVisibleEditors-enabled": true,
"coverage-gutters.showGutterCoverage": true,
"coverage-gutters.showLineCoverage": true,
"coverage-gutters.xmlname": "coverage.xml",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"markdown.extension.toc.levels": "2..6",
"markdown.extension.toc.omittedFromToc": {
"docs/1_basic_usage.md": ["## Documentation"],
"docs/2_documents.md": ["## Documentation"],
"docs/3_custom_fields.md": ["## Documentation"],
"docs/4_permissions.md": ["## Documentation"]
},
"python.defaultInterpreterPath": "/home/vscode/.local/dev-venv/bin/python",
"python.pythonPath": "/home/vscode/.local/dev-venv/bin/python",
"python.terminal.activateEnvInCurrentTerminal": true,
"python.testing.pytestArgs": [
"--no-cov",
"--cov-report=term",
"--cov-report=xml"
],
"pylint.importStrategy": "fromEnvironment",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
},
"terminal.integrated.profiles.linux": {
"zsh": {
"path": "/usr/bin/zsh"
}
},
"terminal.integrated.defaultProfile.linux": "zsh"
}
}
}
}
paperless-api-5.1.0/.editorconfig 0000664 0000000 0000000 00000000274 15053074171 0016745 0 ustar 00root root 0000000 0000000 root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 2
[*.md]
trim_trailing_whitespace = false
paperless-api-5.1.0/.gitattributes 0000664 0000000 0000000 00000000051 15053074171 0017154 0 ustar 00root root 0000000 0000000 * text eol=lf
*.py whitespace=error
paperless-api-5.1.0/.github/ 0000775 0000000 0000000 00000000000 15053074171 0015625 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/.github/labels.yml 0000664 0000000 0000000 00000005445 15053074171 0017622 0 ustar 00root root 0000000 0000000 ---
- name: "auto"
color: bfdadc
description: "Marks a PR or issue that has been created automatically."
- name: "breaking-change"
color: ee0701
description: "A breaking change for existing users."
- name: "bugfix"
color: ee0701
description: "Inconsistencies or issues which will cause a problem for users or implementers."
- name: "documentation"
color: 0052cc
description: "Solely about the documentation of the project."
- name: "enhancement"
color: 1d76db
description: "Enhancement of the code, not introducing new features."
- name: "refactor"
color: 1d76db
description: "Improvement of existing code, not introducing new features."
- name: "performance"
color: 1d76db
description: "Improving performance, not introducing new features."
- name: "new-feature"
color: 0e8a16
description: "New features or options."
- name: "maintenance"
color: 2af79e
description: "Generic maintenance tasks."
- name: "ci"
color: 1d76db
description: "Work that improves the continuous integration."
- name: "dependencies"
color: 1d76db
description: "Upgrade or downgrade of project dependencies."
- name: "in-progress"
color: fbca04
description: "Issue is currently being resolved by a developer."
- name: "stale"
color: fef2c0
description: "There has not been activity on this issue or PR for quite some time."
- name: "no-stale"
color: fef2c0
description: "This issue or PR is exempted from the stale bot."
- name: "security"
color: ee0701
description: "Marks a security issue that needs to be resolved asap."
- name: "incomplete"
color: fef2c0
description: "Marks a PR or issue that is missing information."
- name: "invalid"
color: fef2c0
description: "Marks a PR or issue that is missing information."
- name: "beginner-friendly"
color: 0e8a16
description: "Good first issue for people wanting to contribute to the project."
- name: "help-wanted"
color: 0e8a16
description: "We need some extra helping hands or expertise in order to resolve this."
- name: "priority-critical"
color: ee0701
description: "This should be dealt with ASAP. Not fixing this issue would be a serious error."
- name: "priority-high"
color: b60205
description: "After critical issues are fixed, these should be dealt with before any further issues."
- name: "priority-medium"
color: 0e8a16
description: "This issue may be useful, and needs some attention."
- name: "priority-low"
color: e4ea8a
description: "Nice addition, maybe... someday..."
- name: "major"
color: b60205
description: "This PR causes a major version bump in the version number."
- name: "minor"
color: 0e8a16
description: "This PR causes a minor version bump in the version number."
- name: "skip-changelog"
color: bfdadc
description: "This PR causes no version bump and won't be displayed in the changelog."
paperless-api-5.1.0/.github/release-drafter.yml 0000664 0000000 0000000 00000002007 15053074171 0021414 0 ustar 00root root 0000000 0000000 ---
name-template: "v$RESOLVED_VERSION ๐"
tag-template: "v$RESOLVED_VERSION"
change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
exclude-labels:
- "skip-changelog"
categories:
- title: "๐จ Breaking changes"
labels:
- "breaking-change"
- title: "โจ New features"
labels:
- "new-feature"
- title: "๐ Bug fixes"
labels:
- "bugfix"
- title: "๐ Enhancements"
labels:
- "enhancement"
- "refactor"
- "performance"
- title: "๐งฐ Maintenance"
labels:
- "maintenance"
- "ci"
- title: "๐ Documentation"
labels:
- "documentation"
- title: "โฌ๏ธ Dependency updates"
labels:
- "dependencies"
version-resolver:
major:
labels:
- "major"
- "breaking-change"
minor:
labels:
- "minor"
- "new-feature"
patch:
labels:
- "bugfix"
- "ci"
- "dependencies"
- "enhancement"
- "performance"
- "refactor"
default: patch
template: |
## Changes
$CHANGES
paperless-api-5.1.0/.github/renovate.json 0000664 0000000 0000000 00000002171 15053074171 0020344 0 ustar 00root root 0000000 0000000 {
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"schedule": ["* 2 1 * *"],
"rebaseWhen": "behind-base-branch",
"dependencyDashboard": true,
"labels": ["auto", "no-stale"],
"lockFileMaintenance": {
"enabled": true,
"automerge": true
},
"commitMessagePrefix": "โฌ๏ธ",
"packageRules": [
{
"matchManagers": ["pip_requirements"],
"enabled": false
},
{
"matchUpdateTypes": ["lockFileMaintenance"],
"addLabels": ["skip-changelog"]
},
{
"matchManagers": ["pep621"],
"addLabels": ["dependencies", "python"],
"rangeStrategy": "bump"
},
{
"matchManagers": ["pep621"],
"matchDepTypes": ["dev"],
"rangeStrategy": "bump"
},
{
"matchManagers": ["pep621"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true
},
{
"matchManagers": ["github-actions"],
"addLabels": ["ci", "github_actions", "skip-changelog"],
"rangeStrategy": "pin"
},
{
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true
}
]
}
paperless-api-5.1.0/.github/workflows/ 0000775 0000000 0000000 00000000000 15053074171 0017662 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/.github/workflows/labels.yml 0000664 0000000 0000000 00000000734 15053074171 0021653 0 ustar 00root root 0000000 0000000 ---
name: Sync labels
# yamllint disable-line rule:truthy
on:
push:
branches:
- main
paths:
- .github/labels.yml
workflow_dispatch:
jobs:
labels:
name: ๐ท Sync labels
runs-on: ubuntu-latest
steps:
- name: โคต๏ธ Check out code from GitHub
uses: actions/checkout@v5.0.0
- name: ๐ Run Label Syncer
uses: micnncim/action-label-syncer@v1.3.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
paperless-api-5.1.0/.github/workflows/linting.yml 0000664 0000000 0000000 00000004130 15053074171 0022047 0 ustar 00root root 0000000 0000000 ---
name: Linting
# yamllint disable-line rule:truthy
on:
pull_request:
paths:
- "**.py"
- "pyproject.toml"
- "uv.lock"
- "pypaperless/**"
- "tests/**"
workflow_dispatch:
env:
DEFAULT_PYTHON: "3.13"
jobs:
lint:
name: ${{ matrix.tool }}
runs-on: ubuntu-latest
strategy:
matrix:
tool: [codespell, ruff, pre-commit-hooks, pylint, yamllint]
steps:
- name: โคต๏ธ Check out code from GitHub
uses: actions/checkout@v5.0.0
- name: ๐ Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: ๐ Set up uv
run: |
pipx install uv
uv venv
- name: ๐ Install Python dependencies
run: uv sync --group dev
- name: ๐ Execute checks
run: |
if [ "${{ matrix.tool }}" = "codespell" ]; then
uv run pre-commit run codespell --all-files
elif [ "${{ matrix.tool }}" = "ruff" ]; then
uv run ruff check --output-format=github .
uv run ruff format --check .
elif [ "${{ matrix.tool }}" = "pre-commit-hooks" ]; then
uv run pre-commit run check-ast --all-files
uv run pre-commit run check-case-conflict --all-files
uv run pre-commit run check-docstring-first --all-files
uv run pre-commit run check-json --all-files
uv run pre-commit run check-merge-conflict --all-files
uv run pre-commit run check-symlinks --all-files
uv run pre-commit run check-toml --all-files
uv run pre-commit run check-yaml --all-files
uv run pre-commit run detect-private-key --all-files
uv run pre-commit run end-of-file-fixer --all-files
uv run pre-commit run trailing-whitespace --all-files
elif [ "${{ matrix.tool }}" = "pylint" ]; then
uv run pre-commit run pylint --all-files
elif [ "${{ matrix.tool }}" = "yamllint" ]; then
uv run yamllint .
fi
paperless-api-5.1.0/.github/workflows/lock.yml 0000664 0000000 0000000 00000000665 15053074171 0021344 0 ustar 00root root 0000000 0000000 ---
name: Lock
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "0 5 * * *"
workflow_dispatch:
jobs:
lock:
name: ๐ Lock closed issues and PRs
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5.0.1
with:
github-token: ${{ github.token }}
issue-inactive-days: "30"
issue-lock-reason: ""
pr-inactive-days: "1"
pr-lock-reason: ""
paperless-api-5.1.0/.github/workflows/pr-labels.yml 0000664 0000000 0000000 00000001412 15053074171 0022264 0 ustar 00root root 0000000 0000000 ---
name: PR Labels
# yamllint disable-line rule:truthy
on:
pull_request_target:
types:
- opened
- synchronize
- labeled
- unlabeled
workflow_call:
jobs:
pr_labels:
name: Verify
runs-on: ubuntu-latest
steps:
- name: ๐ท Verify PR has a valid label
uses: jesusvasquez333/verify-pr-label-action@v1.4.0
with:
pull-request-number: "${{ github.event.pull_request.number }}"
github-token: "${{ secrets.GITHUB_TOKEN }}"
valid-labels: >-
breaking-change, bugfix,
ci,
dependencies, documentation,
enhancement,
maintenance,
new-feature,
performance,
refactor
disable-reviews: true
paperless-api-5.1.0/.github/workflows/release-drafter.yml 0000664 0000000 0000000 00000000572 15053074171 0023456 0 ustar 00root root 0000000 0000000 ---
name: Release Drafter
# yamllint disable-line rule:truthy
on:
push:
branches:
- main
workflow_dispatch:
jobs:
update_release_draft:
name: ๐ Draft release
runs-on: ubuntu-latest
steps:
- name: ๐ Run Release Drafter
uses: release-drafter/release-drafter@v6.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
paperless-api-5.1.0/.github/workflows/release.yml 0000664 0000000 0000000 00000002733 15053074171 0022032 0 ustar 00root root 0000000 0000000 ---
name: Release
# yamllint disable-line rule:truthy
on:
release:
types:
- published
env:
DEFAULT_PYTHON: "3.13"
jobs:
release:
name: Releasing to PyPi
runs-on: ubuntu-latest
environment:
name: release
url: https://pypi.org/p/pypaperless
permissions:
contents: write
id-token: write # important for trusted publishing (pypi)
steps:
- name: โคต๏ธ Check out code from GitHub
uses: actions/checkout@v5.0.0
- name: ๐ Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: ๐ Set up uv
run: |
pipx install uv
uv venv
- name: ๐ Install Python dependencies
run: uv sync --group dev
- name: ๐ Set package version
run: |
version="${{ github.event.release.tag_name }}"
version="${version,,}"
version="${version#v}"
sed -i "s/^version = .*/version = \"${version}\"/" pyproject.toml
- name: ๐ Build package
run: uv build
- name: ๐ Publish to PyPi
uses: pypa/gh-action-pypi-publish@v1.12.4
with:
verbose: true
print-hash: true
- name: โ๏ธ Sign published artifacts
uses: sigstore/gh-action-sigstore-python@v3.0.1
with:
inputs: ./dist/*.tar.gz ./dist/*.whl
release-signing-artifacts: true
paperless-api-5.1.0/.github/workflows/stale.yml 0000664 0000000 0000000 00000002552 15053074171 0021521 0 ustar 00root root 0000000 0000000 ---
name: Stale
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "0 3 * * *"
workflow_dispatch:
jobs:
stale:
name: ๐งน Clean up stale issues and PRs
runs-on: ubuntu-latest
steps:
- name: ๐ Run stale
uses: actions/stale@v9.1.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30
days-before-close: 7
remove-stale-when-updated: true
stale-issue-label: "stale"
exempt-issue-labels: "no-stale,help-wanted"
stale-issue-message: >
There hasn't been any activity on this issue recently, so we have to
clean up some inactive issues.
Please make sure to update to the latest version and
check if that solves the issue. Let us know if that works for you
by leaving a comment ๐
This issue has now been marked as stale and will be closed if no
further activity occurs. Thank you.
stale-pr-label: "stale"
exempt-pr-labels: "no-stale"
stale-pr-message: >
There hasn't been any activity on this pull request recently. This
pull request has been automatically marked as stale because of that
and will be closed if no further activity occurs within 7 days.
Thank you for your contribution!
paperless-api-5.1.0/.github/workflows/tests.yml 0000664 0000000 0000000 00000003071 15053074171 0021550 0 ustar 00root root 0000000 0000000 ---
name: Testing
# yamllint disable-line rule:truthy
on:
pull_request:
paths:
- "**.py"
- "pyproject.toml"
- "uv.lock"
- "pypaperless/**"
- "tests/**"
workflow_dispatch:
env:
DEFAULT_PYTHON: "3.13"
jobs:
pytest:
name: Python ${{ matrix.python }}
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.12", "3.13"]
steps:
- name: โคต๏ธ Check out code from GitHub
uses: actions/checkout@v5.0.0
- name: ๐ Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: ๐ Set up uv
run: |
pipx install uv
uv venv
- name: ๐ Install Python dependencies
run: uv sync --group dev
- name: ๐ Run pytest
run: uv run pytest -v --cov-report xml:coverage.xml --cov pypaperless tests
- name: โฌ๏ธ Upload coverage artifact
uses: actions/upload-artifact@v4.6.2
with:
name: coverage-${{ matrix.python }}
path: coverage.xml
coverage:
runs-on: ubuntu-latest
needs: pytest
steps:
- name: โคต๏ธ Check out code from GitHub
uses: actions/checkout@v5.0.0
with:
fetch-depth: 0
- name: โฌ๏ธ Download coverage data
uses: actions/download-artifact@v5.0.0
- name: ๐ Upload coverage report
uses: codecov/codecov-action@v5.5.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
paperless-api-5.1.0/.github/workflows/typing.yml 0000664 0000000 0000000 00000001463 15053074171 0021723 0 ustar 00root root 0000000 0000000 ---
name: Typing
# yamllint disable-line rule:truthy
on:
pull_request:
paths:
- "**.py"
- "pyproject.toml"
- "uv.lock"
- "pypaperless/**"
- "tests/**"
workflow_dispatch:
env:
DEFAULT_PYTHON: "3.13"
jobs:
mypy:
name: mypy
runs-on: ubuntu-latest
steps:
- name: โคต๏ธ Check out code from GitHub
uses: actions/checkout@v5.0.0
- name: ๐ Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.6.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: ๐ Set up uv
run: |
pipx install uv
uv venv
- name: ๐ Install Python dependencies
run: uv sync --group dev
- name: ๐ Run mypy
run: uv run mypy pypaperless tests
paperless-api-5.1.0/.gitignore 0000664 0000000 0000000 00000002715 15053074171 0016262 0 ustar 00root root 0000000 0000000 # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# OSX useful to ignore
*.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# pyenv
.python-version
# virtualenv
.venv
venv/
ENV/
# mypy
.mypy_cache/
# ruff
.ruff_cache
# Visual Studio Code
.vscode
# IntelliJ Idea family of suites
.idea
*.iml
## File-based project format:
*.ipr
*.iws
## mpeltonen/sbt-idea plugin
.idea_modules/
# PyBuilder
target/
# Cookiecutter
output/
python_boilerplate/
# Node
node_modules/
# Deepcode AI
.dccache
# run
run/
paperless-api-5.1.0/.pre-commit-config.yaml 0000664 0000000 0000000 00000007462 15053074171 0020557 0 ustar 00root root 0000000 0000000 ---
repos:
- repo: https://github.com/renovatebot/pre-commit-hooks
rev: 41.1.4
hooks:
- id: renovate-config-validator
- repo: local
hooks:
- id: ruff-check
name: ๐ถ Ruff Linter
language: system
types: [python]
entry: uv run ruff check --fix
require_serial: true
stages: [pre-commit, pre-push, manual]
- id: ruff-format
name: ๐ถ Ruff Formatter
language: system
types: [python]
entry: uv run ruff format
require_serial: true
stages: [pre-commit, pre-push, manual]
- id: check-ast
name: ๐ Check Python AST
language: system
types: [python]
entry: uv run check-ast
- id: check-case-conflict
name: ๐ Check for case conflicts
language: system
entry: uv run check-case-conflict
- id: check-docstring-first
name: โน๏ธ Check docstring is first
language: system
types: [python]
entry: uv run check-docstring-first
# - id: check-executables-have-shebangs
# name: ๐ง Check that executables have shebangs
# language: system
# types: [text, executable]
# entry: uv run check-executables-have-shebangs
# stages: [commit, push, manual]
- id: check-json
name: ๏ฝ Check JSON files
language: system
types: [json]
entry: uv run check-json
- id: check-merge-conflict
name: ๐ฅ Check for merge conflicts
language: system
types: [text]
entry: uv run check-merge-conflict
- id: check-symlinks
name: ๐ Check for broken symlinks
language: system
types: [symlink]
entry: uv run check-symlinks
- id: check-toml
name: โ
Check TOML files
language: system
types: [toml]
entry: uv run check-toml
- id: check-xml
name: โ
Check XML files
entry: uv run check-xml
language: system
types: [xml]
- id: check-yaml
name: โ
Check YAML files
language: system
types: [yaml]
entry: uv run check-yaml
- id: codespell
name: โ
Check code for common misspellings
language: system
types: [text]
exclude: ^(uv\.lock|requirements\.txt|requirements_dev.txt)$
entry: uv run codespell
- id: detect-private-key
name: ๐ต๏ธ Detect Private Keys
language: system
types: [text]
entry: uv run detect-private-key
- id: end-of-file-fixer
name: โฎ Fix End of Files
language: system
types: [text]
entry: uv run end-of-file-fixer
stages: [pre-commit, pre-push, manual]
- id: mypy
name: ๐ Static type checking using mypy
language: system
types: [python]
entry: uv run mypy
require_serial: true
- id: no-commit-to-branch
name: ๐ Don't commit to main branch
language: system
entry: uv run no-commit-to-branch
pass_filenames: false
always_run: true
args:
- --branch=main
- id: pylint
name: ๐ Starring code with pylint
language: system
types: [python]
entry: uv run pylint
- id: pytest
name: ๐งช Running tests and test coverage with pytest
language: system
types: [python]
entry: uv run pytest
pass_filenames: false
- id: trailing-whitespace
name: โ Trim Trailing Whitespace
language: system
types: [text]
entry: uv run trailing-whitespace-fixer
stages: [pre-commit, pre-push, manual]
- id: yamllint
name: ๐ Check YAML files with yamllint
language: system
types: [yaml]
entry: uv run yamllint
paperless-api-5.1.0/.vscode/ 0000775 0000000 0000000 00000000000 15053074171 0015626 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/.vscode/launch.json 0000664 0000000 0000000 00000000462 15053074171 0017775 0 ustar 00root root 0000000 0000000 {
"version": "0.2.0",
"configurations": [
{
"name": "Python: pypaperless debug",
"type": "debugpy",
"request": "launch",
"program": "run/debug.py",
"console": "integratedTerminal",
"justMyCode": true
}
]
}
paperless-api-5.1.0/.yamllint 0000664 0000000 0000000 00000002400 15053074171 0016113 0 ustar 00root root 0000000 0000000 ---
ignore:
- .venv
rules:
braces:
level: error
min-spaces-inside: 0
max-spaces-inside: 1
min-spaces-inside-empty: -1
max-spaces-inside-empty: -1
brackets:
level: error
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: -1
max-spaces-inside-empty: -1
colons:
level: error
max-spaces-before: 0
max-spaces-after: 1
commas:
level: error
max-spaces-before: 0
min-spaces-after: 1
max-spaces-after: 1
comments:
level: error
require-starting-space: true
min-spaces-from-content: 1
comments-indentation:
level: error
document-end:
level: error
present: false
document-start:
level: error
present: true
empty-lines:
level: error
max: 1
max-start: 0
max-end: 1
hyphens:
level: error
max-spaces-after: 1
indentation:
level: error
spaces: 2
indent-sequences: true
check-multi-line-strings: false
key-duplicates:
level: error
line-length:
level: warning
max: 120
allow-non-breakable-words: true
allow-non-breakable-inline-mappings: true
new-line-at-end-of-file:
level: error
new-lines:
level: error
type: unix
trailing-spaces:
level: error
truthy:
level: error
paperless-api-5.1.0/Dockerfile.dev 0000664 0000000 0000000 00000002371 15053074171 0017037 0 ustar 00root root 0000000 0000000 FROM mcr.microsoft.com/devcontainers/python:1-3.13
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Uninstall pre-installed formatting and linting tools
# They would conflict with our pinned versions
RUN \
pipx uninstall pydocstyle \
&& pipx uninstall pycodestyle \
&& pipx uninstall mypy \
&& pipx uninstall pylint
RUN \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
# Additional library needed by some tests and accordingly by VScode Tests Discovery
bluez \
ffmpeg \
libudev-dev \
libavformat-dev \
libavcodec-dev \
libavdevice-dev \
libavutil-dev \
libgammu-dev \
libswscale-dev \
libswresample-dev \
libavfilter-dev \
libpcap-dev \
libturbojpeg0 \
libyaml-dev \
libxml2 \
git \
cmake \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install uv
RUN pip3 install uv
USER vscode
ENV VIRTUAL_ENV="/home/vscode/.local/dev-venv"
RUN uv venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
# force use the venv
ENV UV_PROJECT_ENVIRONMENT="$VIRTUAL_ENV"
WORKDIR /workspaces
# Set the default shell to bash instead of sh
ENV SHELL=/bin/bash
paperless-api-5.1.0/LICENSE.md 0000664 0000000 0000000 00000002056 15053074171 0015674 0 ustar 00root root 0000000 0000000 # MIT License
Copyright (c) 2022-2024 tb1337
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
paperless-api-5.1.0/README.md 0000664 0000000 0000000 00000006652 15053074171 0015555 0 ustar 00root root 0000000 0000000 # PyPaperless
[![GitHub Release][release-badge]][release-url]
[![Python Version][python-badge]][python-url]
[![GitHub License][license-badge]][license-url]
[![Tests][tests-badge]][tests-url]
[![Codecov][codecov-badge]][codecov-url]
[![Linting][linting-badge]][linting-url]
[![Typing][typing-badge]][typing-url]
Little asynchronous client for *Paperless-ngx*, written in Python. You should at least use Python `>=3.12`.
## Features
- Depends on aiohttp, works in async environments.
- Token authentication preferred (credentials possible using a URL like https://user:pass@example.com)
- Request single resource items.
- Iterate over all resource items or request them page by page.
- Create, update and delete resource items.
- Add, remove and update custom fields on documents.
- Almost feature complete.
- **pypaperless** is designed to transport data only. Your code must organize it.
Find out more about *Paperless-ngx* here:
- Project: https://docs.paperless-ngx.com
- API Docs: https://docs.paperless-ngx.com/api/
- Source Code: https://github.com/paperless-ngx/paperless-ngx
## Installation
```bash
pip install pypaperless
```
## Documentation
Please check out the **[docs][docs-url]** for detailed instructions and examples.
## Compatibility matrix
Choosing the right version of **pypaperless** for your *Paperless-ngx* instance can be tricky. This little matrix is here to help.
| **pypaperless** | *Paperless-ngx* |
| --------------- | --------------- |
| >= 5.1 | >= 2.17 |
| >= 5.0 | >= 2.17 |
| >= 4.1 | >= 2.16 |
| >= 4.0 | >= 2.15 |
| < 4.0 | < 2.15 |
* **pypaperless** `<4.0` is not compatible with *Paperless-ngx* `>=2.15` due to breaking server changes.
* **pypaperless** `>=5.0` implements date changes in the document API and is therefore not compatible with *Paperless-ngx* `<2.17`.
* **pypaperless** `>=5.1` will drop support for all *Paperless-ngx* versions without the Open API schema, introduced in `2.15`.
Consider keeping both *Paperless-ngx* and **pypaperless** always updated.
## Authors & contributors
**pypaperless** is written by [Tobias Schulz][contributors-tbsch]. Its his first Python project. Feedback appreciated.
Check out all [contributors here][contributors-url].
[codecov-badge]: https://codecov.io/gh/tb1337/paperless-api/graph/badge.svg?token=IMXRBK3HRE
[codecov-url]: https://app.codecov.io/gh/tb1337/paperless-api/tree/main
[contributors-tbsch]: https://tbsch.de
[contributors-url]: https://github.com/tb1337/paperless-api/graphs/contributors
[docs-url]: https://github.com/tb1337/paperless-api/blob/main/docs/
[license-badge]: https://img.shields.io/github/license/tb1337/paperless-api
[license-url]: /LICENSE.md
[python-badge]: https://img.shields.io/pypi/pyversions/pypaperless
[python-url]: https://pypi.org/project/pypaperless/
[tests-badge]: https://github.com/tb1337/paperless-api/actions/workflows/tests.yml/badge.svg
[tests-url]: https://github.com/tb1337/paperless-api/actions
[release-badge]: https://img.shields.io/github/v/release/tb1337/paperless-api
[release-url]: https://github.com/tb1337/paperless-api/releases
[linting-badge]: https://github.com/tb1337/paperless-api/actions/workflows/linting.yml/badge.svg
[linting-url]: https://github.com/tb1337/paperless-api/actions
[typing-badge]: https://github.com/tb1337/paperless-api/actions/workflows/typing.yml/badge.svg
[typing-url]: https://github.com/tb1337/paperless-api/actions
paperless-api-5.1.0/docs/ 0000775 0000000 0000000 00000000000 15053074171 0015215 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/docs/1_basic_usage.md 0000664 0000000 0000000 00000026007 15053074171 0020231 0 ustar 00root root 0000000 0000000 # Basic Usage
## Documentation
* [Basic Usage](1_basic_usage.md) - This page ;)
* [Working with documents](2_documents.md)
* [Working with custom fields](3_custom_fields.md)
* [Permissions](4_permissions.md)
---
**On this page:**
- [Starting a session](#starting-a-session)
- [Quickstart](#quickstart)
- [URL rules](#url-rules)
- [Custom session](#custom-session)
- [Creating a token](#creating-a-token)
- [Resource features](#resource-features)
- [Requesting data](#requesting-data)
- [Getting one item by primary key](#getting-one-item-by-primary-key)
- [Retrieving a list of primary keys](#retrieving-a-list-of-primary-keys)
- [Iterating over resource items](#iterating-over-resource-items)
- [Iterating over pages](#iterating-over-pages)
- [Reducing http requests](#reducing-http-requests)
- [Manipulating data](#manipulating-data)
- [Creating new items](#creating-new-items)
- [Updating existing items](#updating-existing-items)
- [Deleting items](#deleting-items)
## Starting a session
### Quickstart
Just import the module and start using it. Note that we must be async.
```python
import asyncio
from pypaperless import Paperless
paperless = Paperless("localhost:8000", "your-secret-token")
# see main() examples
asyncio.run(main())
```
**main() Example 1**
```python
async def main():
await paperless.initialize()
# do something
await paperless.close()
```
**main() Example 2**
```python
async def main():
async with paperless:
# do something
```
### URL rules
There are some rules for the *Paperless-ngx* url.
1. Isn't a scheme applied to it? `https` is automatically used.
2. If you explicitly start with `http`, the connection will be unencrypted (not recommended).
3. Only use the **base url** of your *Paperless-ngx*. Don't add `/api` to it.
### Custom session
You may want to use an existing `aiohttp.ClientSession` in some cases. Simply pass it to the `Paperless` object.
```python
import aiohttp
from pypaperless import Paperless
my_session = aiohttp.ClientSession()
# ...
paperless = Paperless("localhost:8000", "your-secret-token", session=my_session)
```
### Creating a token
**pypaperless** needs an API token to request and send data from and to *Paperless-ngx* for authentication purposes. It is recommended to create a technical user and assign a token to it via Django Admin, when you bootstrap any project with **pypaperless**. If you need to create that token by providing credentials, **pypaperless** ships with a little helper for that task.
```python
token = Paperless.generate_api_token(
"localhost:8000",
"test_user",
"your-password-here",
)
```
As for `Paperless` itself, you can provide a custom `aiohttp.ClientSession` object.
```python
url = "localhost:8000"
my_session = aiohttp.ClientSession()
token = Paperless.generate_api_token(
"localhost:8000",
"test_user",
"not-so-secret-password-anymore",
session=my_session,
)
```
> [!CAUTION]
> Hardcoding credentials or tokens is never good practise. Use that with caution.
> [!NOTE]
> Executed http requests:
> `POST` `https://localhost:8000/api/token/`
## Resource features
| Resource | Request | Iterate | Create | Update | Delete | Permissions |
| -------------- | -------- | ------- | ------ | ------ | ------ | ----------- |
| config | x |
| correspondents | x | x | x | x | x | x |
| custom_fields | x | x | x | x | x |
| document_types | x | x | x | x | x | x |
| documents | x | x | x | x | x | x |
| groups | x | x |
| logs | **n.a.** |
| mail_accounts | x | x | | | | x |
| mail_rules | x | x | | | | x |
| saved_views | x | x | | | | x |
| share_links | x | x | x | x | x |
| statistics | x |
| status | x |
| storage_paths | x | x | x | x | x | x |
| tags | x | x | x | x | x | x |
| tasks | x | x\* | | |
| users | x | x | | |
| workflows | x | x | | |
\*: Only `__aiter__` is supported.
`logs` are not implemented, as they return plain text. Since logs return plain text, support for this resource is currently not implemented.
## Requesting data
Retrieving data from *Paperless-ngx* is really easy, there are different possibilities to achieve that.
### Getting one item by primary key
This is the most common use case, since **pypaperless** always returns references to other resource items by their primary keys. You must resolve these references on your own. The returned objects are always `PaperlessModel`s.
```python
document = await paperless.documents(1337)
doc_type = await paperless.document_types(document.document_type) # 23
print(f"Document '{document.title}' is an {doc_type.name}.")
#-> Document 'Order #23: Desktop Table' is an Invoice.
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/1337/`
> `GET` `https://localhost:8000/api/document_types/23/`
### Retrieving a list of primary keys
Since resource items are requested by their primary key, it could be useful to request a list of all available primary keys.
```python
item_keys = await paperless.documents.all()
#-> [1, 2, 3, ...]
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/?page=1`
### Iterating over resource items
Iteration enables you to execute mass operations of any kind. Like requesting single items, the iterator always returns `PaperlessModel`s.
```python
count = 0
async for item in paperless.documents:
if item.correspondent == 1:
count += 1
print(f"{count} documents are currently stored for correspondent 1.")
#-> 5 documents are currently stored for correspondent 1.
```
> [!NOTE]
> The code above executes many http requests, depending on the count of your stored documents:
> `GET` `https://localhost:8000/api/documents/?page=1`
> `GET` `https://localhost:8000/api/documents/?page=2`
> `...`
> `GET` `https://localhost:8000/api/documents/?page=19`
### Iterating over pages
Instead of iterating over resource items, you may want to iterate over pagination results in some cases. The `Page` model itself delivers the possibility to check for the existence of previous and next pages, item counts, accessing the raw (`.results`) or processed data (`.items`), and so on.
```python
page_iter = aiter(paperless.documents.pages())
page = await anext(page_iter)
#-> page.current_page == 1
page = await anext(page_iter)
#-> page.current_page == 2
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/?page=1`
> `GET` `https://localhost:8000/api/documents/?page=2`
### Reducing http requests
Requesting many pages can be time-consuming, so a better way to apply the filter (mentioned [here](#iterating-over-resource-items)) is to use the `reduce` context manager. Technically, it applies query parameters to the http request, which are interpreted as filters by *Paperless-ngx*.
```python
filters = {
"correspondent__id": 1,
}
async with paperless.documents.reduce(**filters) as filtered:
async for item in filtered:
count += 1
# ...
#-> 5 documents are currently stored for correspondent 1.
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/?page=1&correspondent__id=1`
> [!TIP]
> The `reduce` context works with all previously mentioned methods: `__aiter__`, `all` and `pages`.
> [!IMPORTANT]
> There are many filters available, **pypaperless** doesn't provide a complete list. I am working on it. At the moment, you must use the Django Rest framework http endpoint of *Paperless-ngx* in your browser and experiment with the **Filter** button on each resource.
>
> *Paperless-ngx* simply ignores filters which don't exist and treats them as no filter instead of raising errors, be careful.
## Manipulating data
**pypaperless** offers creation, update and deletion of resource items. These features are enabled where it makes (at least for me) sense, *Paperless-ngx* itself offers full CRUD functionality. Please check the [resource features](#resource-features) table at the top of this README. If you need CRUD for another resource, please let me know and open an [issue](https://github.com/tb1337/paperless-api/issues) with your specific use-case.
### Creating new items
The process of creating items consists of three parts: retrieving a new draft instance from **pypaperless**, apply data to it and call `save`. You can choose whether applying data to the draft via `kwargs` or by assigning it to the draft instance, or both. If you do not need to further use the created item, the draft instance can be safely discarded after saving, as it cannot be reused (database constraint violation).
```python
from pypaperless.models.common import MatchingAlgorithmType
draft = paperless.correspondents.draft(
name="New correspondent",
is_insensitive=True, # this works
)
draft.matching_algorithm = MatchingAlgorithmType.ANY
draft.match = 'any word "or small strings" match'
draft.is_insensitive = False # and this, too!
new_pk = await draft.save()
#-> 42
```
> [!NOTE]
> Executed http requests:
> `POST` `https://localhost:8000/api/correspondents/`
### Updating existing items
When it comes to updating data, you can choose between http `PATCH` (only changed fields) or `PUT` (all fields) methods. Usually updating only changed fields will do the trick. You can continue working with the class instance after updating, as the `update` method applies new data from *Paperless-ngx* to it.
```python
item = await paperless.documents(23)
item.title = "New document title"
success = await item.update()
success = await item.update(only_changed=False) # put all fields
#-> True
```
> [!NOTE]
> Executed http requests:
> `PATCH` `http://localhost:8000/api/documents/23/`
> **OR**
> `PUT` `http://localhost:8000/api/documents/23/`
> [!TIP]
> The actual payload of the request is completely different here, and I recommend you to use `PATCH` whenever possible. It is cleaner and much safer, as it only updates fields which have _actually_ changed.
**PATCH**
```json
{
"title": "New document title"
}
```
**PUT**
```json
{
"title": "New document title",
"content": "...",
"correspondents": ["..."],
"document_types": ["..."],
"storage_paths": ["..."],
"...": "..."
// and every other field
}
```
### Deleting items
Last but not least, it is also possible to remove data from *Paperless-ngx*.
> [!CAUTION]
> This will permanently delete data from your database. There is no point of return. Be careful.
```python
item = await paperless.documents(23)
success = await item.delete()
#-> True
```
> [!NOTE]
> Executed http requests:
> `DELETE` `http://localhost:8000/api/documents/23/`
paperless-api-5.1.0/docs/2_documents.md 0000664 0000000 0000000 00000016721 15053074171 0017770 0 ustar 00root root 0000000 0000000 # Working with documents
Some *Paperless-ngx* resources provide more features as others, especially when it comes to `Documents`. Lets take a closer look!
## Documentation
* [Basic Usage](1_basic_usage.md)
* [Working with documents](2_documents.md) - This page ;)
* [Working with custom fields](3_custom_fields.md)
* [Permissions](4_permissions.md)
---
**On this page:**
- [Binary image/pdf data](#binary-imagepdf-data)
- [Lookup specific documents](#lookup-specific-documents)
- [1. Search query](#1-search-query)
- [2. More like](#2-more-like)
- [Search results](#search-results)
- [Metadata](#metadata)
- [Notes](#notes)
- [Suggestions](#suggestions)
- [Next available ASN](#next-available-asn)
## Binary image/pdf data
You can access the binary image/pdf data by using the following methods. They all return a `DownloadedDocument` class instance, which holds the actual binary data and provides some more useful attributes, like content type, disposition type and filename.
**Example 1: Provide a primary key**
```python
download = await paperless.documents.download(23)
preview = await paperless.documents.preview(23)
thumbnail = await paperless.documents.thumbnail(23)
```
**Example 2: Already fetched item**
```python
document = await paperless.documents(23)
download = await document.get_download()
preview = await document.get_preview()
thumbnail = await document.get_thumbnail()
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/download/`
> `GET` `https://localhost:8000/api/documents/23/preview/`
> `GET` `https://localhost:8000/api/documents/23/thumb/`
## Lookup specific documents
If you want to search for documents, *Paperless-ngx* offers two possibilities to achieve that. **pypaperless** implements two iterable shortcuts for that.
### 1. Search query
Search query documentation: https://docs.paperless-ngx.com/usage/#basic-usage_searching
```python
async for document in paperless.documents.search("type:invoice"):
# do something
```
> [!NOTE]
> The code above executes many http requests, depending on the count of your matched documents:
> `GET` `https://localhost:8000/api/documents/?page=1&query=type%3Ainvoice`
> `GET` `https://localhost:8000/api/documents/?page=2&query=type%3Ainvoice`
> `...`
> `GET` `https://localhost:8000/api/documents/?page=19&query=type%3Ainvoice`
### 2. More like
Search for similar documents like the permitted document primary key.
```python
async for document in paperless.documents.more_like(23):
# do something
```
> [!NOTE]
> The code above executes many http requests, depending on the count of your matched documents:
> `GET` `https://localhost:8000/api/documents/?page=1&more_like_id=23`
> `GET` `https://localhost:8000/api/documents/?page=2&more_like_id=23`
> `...`
> `GET` `https://localhost:8000/api/documents/?page=19&more_like_id=23`
### Search results
While iterating over search results, `Document` models are extended with another field: `search_hit`. Lets take a closer look at it.
```python
async for document in paperless.documents.more_like(23):
print(f"{document.id} matched query by {document.search_hit.score}.")
#-> 42 matched query by 13.37.
```
To make life easier, you have the possibility to check whether a `Document` model has been initialized from a search or not:
```python
document = await paperless.documents(23) # no search
if document.has_search_hit:
print("result of a search query")
else:
print("not a result from a query")
#-> not a result from a query
```
## Metadata
*Paperless-ngx* stores some metadata about your documents. If you wish to access them, there are two ways to achieve that.
**Example 1: Provide a primary key**
```python
metadata = await paperless.documents.metadata(23)
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/metadata/`
**Example 2: Already fetched item**
```python
document = await paperless.documents(23)
metadata = await document.get_metadata()
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/`
> `GET` `https://localhost:8000/api/documents/23/metadata/`
## Notes
Documents can be commented with so-called notes. *Paperless-ngx* supports requesting, creating and deleting those. **pypaperless** includes built-in support for it, too.
**Getting notes**
Document notes are always available as `list[DocumentNote]` after requesting them.
There are two ways of requesting document notes:
```python
# by primary key
list_of_notes = await paperless.documents.notes(23)
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/notes/`
or
```python
# by already fetched item
document = await paperless.documents(23)
list_of_notes = await document.notes()
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/`
> `GET` `https://localhost:8000/api/documents/23/notes/`
**Creating notes**
You can add new notes. Updating existing notes isn't possible due to *Paperless-ngx* API limitations.
There are two ways of creating a new note draft:
```python
# by document primary key
draft = paperless.documents.notes.draft(23)
```
or
```python
# by already fetched document
document = await paperless.documents(23)
draft = document.notes.draft()
```
After creating the draft, do your work with it and tell *Paperless-ngx* to store it:
```python
draft.note = "Lorem ipsum"
new_note_pk, document_pk = await draft.save()
#-> 42, 23
```
> [!NOTE]
> Executed http requests:
> `POST` `https://localhost:8000/api/documents/23/notes/`
**Deleting notes**
Sometimes it may be necessary to delete document notes.
> [!CAUTION]
> This will permanently delete data from your database. There is no way to recover deleted data. Be careful.
```python
a_note = list_of_notes.pop() # document note with example pk 42
success = await a_note.delete()
#-> True
```
> [!NOTE]
> Executed http requests:
> `DELETE` `https://localhost:8000/api/documents/23/notes/?id=42`
## Suggestions
One of the key functionalities of *Paperless-ngx* is _classification_: it is the workflow of assigning classifiers to your documents, like correspondents or tags. *Paperless-ngx* does that by auto-assigning or suggesting them to you. These suggestions can be accessed by **pypaperless**, as well.
**Example 1: Provide a primary key**
```python
suggestions = await paperless.documents.suggestions(23)
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/suggestions/`
**Example 2: Already fetched item**
```python
document = await paperless.documents(23)
suggestions = await document.get_suggestions()
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/`
> `GET` `https://localhost:8000/api/documents/23/suggestions/`
The returned `DocumentSuggestions` instance stores a list of suggested resource items for each classifier: correspondents, tags, document_types, storage_paths and dates.
This is what the raw data looks like:
```json
{
"correspondents": [
11
],
"tags": [1, 33, 7],
"document_types": [
15
],
"storage_paths": [
2
],
"dates": [
"2023-01-02",
"2024-03-04",
"2025-05-06"
]
}
```
## Next available ASN
Simply returns the next available archive serial number as `int`.
```python
next_asn = await paperless.documents.get_next_asn()
#-> 1337
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/next_asn/`
paperless-api-5.1.0/docs/3_custom_fields.md 0000664 0000000 0000000 00000027036 15053074171 0020631 0 ustar 00root root 0000000 0000000 # Working with custom fields
When classifying your documents, you may want to add custom fields to them. As of `v5.0`, **pypaperless** introduces a completely new way of working with them!
## Documentation
* [Basic Usage](1_basic_usage.md)
* [Working with documents](2_documents.md)
* [Working with custom fields](3_custom_fields.md) - This page ;)
* [Permissions](4_permissions.md)
---
**On this page:**
- [Introduction to custom fields](#introduction-to-custom-fields)
- [Caching](#caching)
- [Providing a cache](#providing-a-cache)
- [Without cache](#without-cache)
- [Checking for custom fields](#checking-for-custom-fields)
- [Iterating over custom fields](#iterating-over-custom-fields)
- [Fetching custom field values](#fetching-custom-field-values)
- [Without fallback (get)](#without-fallback-get)
- [With fallback (default)](#with-fallback-default)
- [Adding custom fields to a document](#adding-custom-fields-to-a-document)
- [Draft a new value](#draft-a-new-value)
- [Attaching to a document](#attaching-to-a-document)
- [Removing custom fields from a document](#removing-custom-fields-from-a-document)
- [Choose a custom field](#choose-a-custom-field)
- [Detach it from document](#detach-it-from-document)
- [Updating custom field values](#updating-custom-field-values)
- [Special custom field data types](#special-custom-field-data-types)
- [Date](#date)
- [Document reference](#document-reference)
- [Monetary](#monetary)
- [Select](#select)
## Introduction to custom fields
In *Paperless-ngx*, custom fields allow you to enrich your documents with additional, structured data. Prior to `v5.0`, working with them was cumbersome: you had to loop through field IDs and values, manually resolve field metadata, and handle parsing based on their types.
Here is an example of how the *Paperless-ngx* API returns custom field instances:
```json
{
"custom_fields": [
{
"value": 42,
"field": 11
},
]
}
```
As you can see, this only gives you the fieldโs ID. To get more details (like its name, type, or metadata), you must fetch the full `CustomField`:
```json
{
"id": 1,
"name": "Very Important Document (VID)",
"data_type": "boolean",
"extra_data": {
"select_options": [
null
],
"default_currency": null
},
"document_count": 23
}
```
To simplify this, **pypaperless** now provides a smarter, more convenient interface for interacting with custom fields.
## Caching
### Providing a cache
You can now cache the list of custom fields for your *Paperless-ngx* instance. This allows **pypaperless** to map fields to rich model classes automatically when documents are fetched:
```python
# initialize the cache
paperless.cache.custom_fields = await paperless.custom_fields.as_dict()
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/custom_fields/`
Now, when you fetch a document, its fields are automatically mapped to their corresponding typed value objects:
```python
document = await paperless.documents(1337)
print(list(document.custom_fields))
#-> [
# CustomFieldIntegerValue(field=1, value=42, name='Any Number Field', data_type=, extra_data={'select_options': [None], 'default_currency': None}),
# CustomFieldBooleanValue(field=3, value=True, ...),
# CustomFieldSelectValue(field=5, ...)
# ]
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/1337/`
### Without cache
If you donโt provide a cache, custom fields are returned as generic `CustomFieldValue` instances:
```python
print(list(document.custom_fields))
#-> [
# CustomFieldValue(field=1, value=42),
# CustomFieldValue(field=3, value=True),
# CustomFieldValue(field=5, ...)
# ]
```
> [!TIP]
> This approach can be useful in scenarios where you're certain that, for example, field 1 contains the integer value you need to operate on.
## Checking for custom fields
To check whether a custom field is attached to a document:
**Example 1: using a `CustomField` instance**
```python
specific_custom_field = await paperless.custom_fields(1)
if specific_custom_field in document.custom_fields:
print("Custom field 1 is present!")
else:
print("Custom field 1 is missing!")
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/custom_fields/1/`
**Example 2: using the field's ID**
```python
custom_field_id = 1
field = document.custom_fields.get(custom_field_id)
# do something with: field.value
```
## Iterating over custom fields
To iterate through all custom fields of a document:
```python
for field in document.custom_fields:
# do something
```
## Fetching custom field values
Its time to work with specific custom field values. **pypaperless** provides different ways to retrieve the actual value of a field.
### Without fallback (get)
> [!CAUTION]
> Note that `document.custom_fields.get(...)` will raise `ItemNotFoundError` if the given custom field doesn't exist in the document data. If that could happen and you prefer not to perform an existence check before, you should use `.default(...)`.
**Example 1: using `CustomField` instance**
```python
specific_custom_field = await paperless.custom_fields(1)
field = document.custom_fields.get(specific_custom_field)
print(field.value)
#-> 42
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/custom_fields/1/`
**Example 2: using the field's ID**
```python
custom_field_id = 1
field = document.custom_fields.get(custom_field_id)
print(field.value)
#-> 42
```
**Example 3: Type safety**
Due to the dynamic data structure of the *Paperless-ngx* API, static typing for `CustomFieldValue` instances is not possible in your development environment. However, if you don't want to give up type safety during development, you can either use `typing.cast()` or the following approach:
```python
from pypaperless.models.common import CustomFieldIntegerValue
field = document.custom_fields.get(custom_field_id, expected_type=CustomFieldIntegerValue)
```
> [!TIP]
> A `TypeError` is raised if the type of the custom field does not correspond to the expected type.
### With fallback (default)
This avoids errors if the field is missing and returns `None` instead.
**Example 1: using `CustomField` instance**
```python
specific_custom_field = await paperless.custom_fields(1)
if field := document.custom_fields.default(specific_custom_field):
print(field.value)
#-> 42
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/custom_fields/1/`
**Example 2: using the field's ID**
```python
custom_field_id = 1
if field := document.custom_fields.default(custom_field_id):
print(field.value)
#-> 42
```
**Example 3: Type safety**
Just like with `get()`, this method ensures type safety as well.
```python
from pypaperless.models.common import CustomFieldIntegerValue
field = document.custom_fields.default(custom_field_id, expected_type=CustomFieldIntegerValue)
```
> [!TIP]
> A `TypeError` is raised if the type of the custom field does not correspond to the expected type.
## Adding custom fields to a document
If you want to add new custom fields to your documents, you have to draft custom field values and add them to the documents custom fields list.
### Draft a new value
Use the `draft_value` method on a `CustomField`:
**Example 1: with cache ([read about caching](#providing-a-cache))**
```python
my_int_field = await paperless.custom_fields(1)
new_field_value = my_int_field.draft_value(42)
print(new_field_value)
#-> CustomFieldIntegerValue(field=1, value=42, name='My Integer Field', data_type=, ...)
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/custom_fields/1/`
**Example 2: without cache**
```python
new_field_value = my_int_field.draft_value(42)
print(new_field_value)
#-> CustomFieldValue(field=1, value=42, ...)
```
**Example 3: Typing**
There is optional type mapping for your development environment the same way as with `get()` and `default()`. Unlike the previous cases, **no exception is raised** if the type doesn't match.
```python
from pypaperless.models.common import CustomFieldIntegerValue
new_field_value = my_int_field.draft_value(42, expected_type=CustomFieldIntegerValue)
```
### Attaching to a document
The new custom field value is ready to go:
```python
document = await paperless.documents(1337)
document.custom_fields.add(new_field_value)
# or simply use
document.custom_fields += new_field_value
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/1337/`
> [!CAUTION]
> Don't forget to call `document.update()` to persist your change in the *Paperless-ngx* database. You can read more about that [here](1_basic_usage.md#updating-existing-items).
## Removing custom fields from a document
In some cases, you may want to remove custom fields from documents again. It is as easy as adding fields.
### Choose a custom field
You can remove fields in three ways.
**Example 1: using `CustomField` instance**
```python
my_int_field = await paperless.custom_fields(1)
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/custom_fields/1/`
**Example 2: using the field's ID**
```python
my_int_field = 1
```
**Example 3: using `CustomFieldValue` instance**
```python
my_int_field = document.custom_fields.get(1)
```
### Detach it from document
The custom field value is ready to be removed:
```python
document = await paperless.documents(1337)
document.custom_fields.remove(my_int_field)
# or simply use
document.custom_fields -= my_int_field
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/1337/`
> [!CAUTION]
> Don't forget to call `document.update()` to persist your change in the *Paperless-ngx* database. You can read more about that [here](1_basic_usage.md#updating-existing-items).
## Updating custom field values
As with every other entity in **pypaperless**, custom field values can be manipulated by just setting a new value to them.
**Example 1: integer custom field**
```python
document = await paperless.documents(1337)
if field := document.custom_fields.default(1):
field.value = 23
await document.update()
```
**Example 2: monetary custom field**
This custom field value is one of the special cases, [scroll down](#monetary) to read more about them.
```python
document = await paperless.documents(1337)
if field := document.custom_fields.default(2):
field.amount = 42.23
await document.update()
print(field.value)
#-> EUR42.23
```
## Special custom field data types
There are many data types for custom fields in *Paperless-ngx*, for example, strings and integers. While both are very common, special data types are also available. **pypaperless** provides some extra functionality for these.
### Date
Values in `CustomFieldDateValue` are parsed into `datetime.date`. If parsing fails, the raw string or `None` is returned.
### Document reference
Returns a list of document IDs. You can fetch full documents manually if needed.
### Monetary
Monetary values such as `EUR123.45` are exposed via:
* `.amount`: Gets or sets the actual amount.
* `.currency`: Gets or sets the currency (EUR, USD, ...).
> [!WARNING]
> Input is not validated client-side. Invalid values will trigger API errors.
### Select
The `CustomFieldSelectValue` raw value is set to an internal ID by *Paperless-ngx*. **pypaperless** ships with properties which resolve the real values for you.
* `.label`: Returns the label for `value` or falls back to `None`.
* `.labels`: Returns the list of labels of the `CustomField`.
paperless-api-5.1.0/docs/4_permissions.md 0000664 0000000 0000000 00000005721 15053074171 0020342 0 ustar 00root root 0000000 0000000 # Permissions
Some resources of *Paperless-ngx* support retrieving and updating of object-level permissions. They are tricky, so here is little guidance for handling them.
## Documentation
* [Basic Usage](1_basic_usage.md)
* [Working with documents](2_documents.md)
* [Working with custom fields](3_custom_fields.md)
* [Permissions](4_permissions.md) - This page ;)
---
**On this page:**
- [About permissions in **pypaperless**](#about-permissions-in-pypaperless)
- [Toggle requesting](#toggle-requesting)
- [Create item with permissions](#create-item-with-permissions)
- [Update permissions](#update-permissions)
## About permissions in **pypaperless**
At the moment, **pypaperless** provides only minimal support for permissions. Due to the way *Paperless-ngx* implements and exposes object-level permissions via the Django API, itโs hard to envision practical use cases for managing them automatically.
> [!CAUTION]
> The permission model is subject to change in the future, when I feel the need for it.
## Toggle requesting
When requesting data from *Paperless-ngx*, it delivers two permission fields by default: `owner` and `user_can_change`.
You have to explicitly call the API to return the permissions table by enabling that feature. To do so, you have to enable it one by one for each resource in **pypaperless**.
```python
paperless.documents.request_permissions = True
document = await paperless.documents(23)
print(document.has_permissions)
#-> True
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/?full_perms=true`
Requesting permissions stays enabled until it gets disabled again.
```python
paperless.documents.request_permissions = False
document = await paperless.documents(23)
print(document.has_permissions)
#-> False
```
> [!NOTE]
> Executed http requests:
> `GET` `https://localhost:8000/api/documents/23/`
## Create item with permissions
When creating new resource items, you can apply permissions by setting a `PermissionTableType` to the optional `set_permissions` field.
> [!WARNING]
> Both `PermissionTableType` and `PermissionSetType` automatically initialize empty lists for their fields unless you provided a value.
```python
from pypaperless.models.common import PermissionSetType, PermissionTableType
draft = paperless.correspondents.draft()
draft.name = "Correspondent with perms"
draft.set_permissions = PermissionTableType(
view=PermissionSetType(
users=[23],
),
)
# ...
```
## Update permissions
If you want to change permissions of a resource item, you have to enable requesting them before fetching it. The `permissions` field gets available then, ready for modifications.
```python
paperless.documents.request_permissions = True
document = await paperless.documents(23)
if document.has_permissions:
document.permissions.view.users.append(5)
await document.update()
```
> [!NOTE]
> Executed http requests:
> `PATCH` `https://localhost:8000/api/documents/23/?full_perms=true`
paperless-api-5.1.0/docs/README.md 0000664 0000000 0000000 00000000263 15053074171 0016475 0 ustar 00root root 0000000 0000000 # Documentation
* [Basic Usage](1_basic_usage.md)
* [Working with documents](2_documents.md)
* [Working with custom fields](3_custom_fields.md)
* [Permissions](4_permissions.md)
paperless-api-5.1.0/pypaperless/ 0000775 0000000 0000000 00000000000 15053074171 0016634 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pypaperless/__init__.py 0000664 0000000 0000000 00000000111 15053074171 0020736 0 ustar 00root root 0000000 0000000 """PyPaperless."""
from .api import Paperless
__all__ = ("Paperless",)
paperless-api-5.1.0/pypaperless/api.py 0000664 0000000 0000000 00000030662 15053074171 0017766 0 ustar 00root root 0000000 0000000 """PyPaperless."""
import logging
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from io import BytesIO
from json.decoder import JSONDecodeError
from typing import Any, Protocol
import aiohttp
from yarl import URL
from . import helpers
from .const import API_PATH, API_VERSION, PaperlessResource
from .exceptions import (
BadJsonResponseError,
InitializationError,
JsonResponseWithError,
PaperlessConnectionError,
PaperlessForbiddenError,
PaperlessInactiveOrDeletedError,
PaperlessInvalidTokenError,
)
from .models.base import HelperBase
from .models.common import PaperlessCache
class PaperlessProtocol(Protocol):
"""Protocol for `Paperless` instances."""
config: helpers.ConfigHelper
correspondents: helpers.CorrespondentHelper
custom_fields: helpers.CustomFieldHelper
documents: helpers.DocumentHelper
document_types: helpers.DocumentTypeHelper
groups: helpers.GroupHelper
mail_accounts: helpers.MailAccountHelper
mail_rules: helpers.MailRuleHelper
saved_views: helpers.SavedViewHelper
share_links: helpers.ShareLinkHelper
statistics: helpers.StatisticHelper
remote_version: helpers.RemoteVersionHelper
status: helpers.StatusHelper
storage_paths: helpers.StoragePathHelper
tags: helpers.TagHelper
tasks: helpers.TaskHelper
users: helpers.UserHelper
workflows: helpers.WorkflowHelper
class Paperless(PaperlessProtocol):
"""Retrieves and manipulates data from and to Paperless via REST."""
_helper_map: dict[str, type[HelperBase]] = {
PaperlessResource.CONFIG: helpers.ConfigHelper,
PaperlessResource.CORRESPONDENTS: helpers.CorrespondentHelper,
PaperlessResource.CUSTOM_FIELDS: helpers.CustomFieldHelper,
PaperlessResource.DOCUMENTS: helpers.DocumentHelper,
PaperlessResource.DOCUMENT_TYPES: helpers.DocumentTypeHelper,
PaperlessResource.GROUPS: helpers.GroupHelper,
PaperlessResource.MAIL_ACCOUNTS: helpers.MailAccountHelper,
PaperlessResource.MAIL_RULES: helpers.MailRuleHelper,
PaperlessResource.SAVED_VIEWS: helpers.SavedViewHelper,
PaperlessResource.SHARE_LINKS: helpers.ShareLinkHelper,
PaperlessResource.STATISTICS: helpers.StatisticHelper,
PaperlessResource.REMOTE_VERSION: helpers.RemoteVersionHelper,
PaperlessResource.STATUS: helpers.StatusHelper,
PaperlessResource.STORAGE_PATHS: helpers.StoragePathHelper,
PaperlessResource.TAGS: helpers.TagHelper,
PaperlessResource.TASKS: helpers.TaskHelper,
PaperlessResource.USERS: helpers.UserHelper,
PaperlessResource.WORKFLOWS: helpers.WorkflowHelper,
}
async def __aenter__(self) -> "Paperless":
"""Return context manager."""
await self.initialize()
return self
async def __aexit__(self, *_: object) -> None:
"""Exit context manager."""
await self.close()
def __init__(
self,
url: str | URL,
token: str | None = None,
*,
session: aiohttp.ClientSession | None = None,
request_args: dict[str, Any] | None = None,
request_api_version: int | None = None,
) -> None:
"""Initialize a `Paperless` instance.
You have to permit either a session, or an url / token pair.
`url`: A hostname or IP-address as string, or yarl.URL object.
`token`: An api token created in Paperless Django settings, or via the helper function.
`session`: A custom `PaperlessSession` object, if existing.
`request_args` are passed to each request method call as additional kwargs,
ssl stuff for example. You should read the aiohttp docs to learn more about it.
"""
self._base_url = self._create_base_url(url)
self._cache = PaperlessCache()
self._initialized = False
self._request_api_version = request_api_version or API_VERSION
self._request_args = request_args or {}
self._session = session
self._token = token
self._api_version = API_VERSION
self._version: str | None = None
self.logger = logging.getLogger(f"{__package__}")
@property
def base_url(self) -> str:
"""Return the base url of the Paperless api endpoint."""
return str(self._base_url)
@property
def cache(self) -> PaperlessCache:
"""Return the cache object."""
return self._cache
@property
def is_initialized(self) -> bool:
"""Return `True` if connection is initialized."""
return self._initialized
@property
def host_api_version(self) -> int:
"""Return the api version of the Paperless host."""
return self._api_version
@property
def host_version(self) -> str | None:
"""Return the version of the Paperless host."""
return self._version
@staticmethod
def _create_base_url(url: str | URL) -> URL:
"""Create URL from string or URL and prepare for further use."""
# reverse compatibility, fall back to https
if isinstance(url, str):
if "://" not in url:
url = f"https://{url}"
url = url.rstrip("/")
url = URL(url)
# scheme check. fall back to https
if url.scheme not in ("https", "http"):
url = URL(url).with_scheme("https")
return url
@staticmethod
def _process_form(data: dict[str, Any]) -> aiohttp.FormData:
"""Process form data and create a `aiohttp.FormData` object.
Every field item gets converted to a string-like object.
"""
form = aiohttp.FormData(quote_fields=False)
def _add_form_value(name: str | None, value: Any) -> Any:
if value is None:
return
params = {}
if isinstance(value, dict):
for dict_key, dict_value in value.items():
_add_form_value(dict_key, dict_value)
return
if isinstance(value, list | set):
for list_value in value:
_add_form_value(name, list_value)
return
if isinstance(value, tuple):
if len(value) == 2:
params["filename"] = f"{value[1]}"
value = value[0]
if name is not None:
form.add_field(
name, BytesIO(value) if isinstance(value, bytes) else f"{value}", **params
)
_add_form_value(None, data)
return form
@staticmethod
async def generate_api_token(
url: str,
username: str,
password: str,
session: aiohttp.ClientSession | None = None,
) -> str:
"""Request Paperless to generate an api token for the given credentials.
Warning: the request is plain and insecure. Don't use this in production
environments or businesses.
Warning: error handling is low for this method, as it is just a helper.
Example:
-------
```python
token = Paperless.generate_api_token("example.com:8000", "api_user", "secret_password")
paperless = Paperless("example.com:8000", token)
# do something
```
"""
external_session = session is not None
session = session or aiohttp.ClientSession()
try:
url = url.rstrip("/")
json = {
"username": username,
"password": password,
}
res = await session.request("post", f"{url}{API_PATH['token']}", json=json)
data = await res.json()
res.raise_for_status()
return str(data["token"])
except (JSONDecodeError, KeyError) as exc:
message = "Token is missing in response."
raise BadJsonResponseError(message) from exc
except aiohttp.ClientResponseError as exc:
raise JsonResponseWithError(payload={"error": data}) from exc
finally:
if not external_session:
await session.close()
async def close(self) -> None:
"""Clean up connection."""
if self._session:
await self._session.close()
self.logger.info("Closed.")
async def initialize(self) -> None:
"""Initialize and test the connection to DRF."""
async with self.request("get", API_PATH["index"]) as res:
try:
res.raise_for_status()
self._api_version = self._request_api_version or int(
res.headers.get("x-api-version", API_VERSION)
)
self._version = res.headers.get("x-version", None)
await res.json()
except (aiohttp.ClientResponseError, JSONDecodeError) as exc:
raise InitializationError from exc
# initialize helpers
for attr, helper_cls in self._helper_map.items():
setattr(self, attr, helper_cls(self))
self._initialized = True
self.logger.info("Initialized.")
@asynccontextmanager
async def request( # noqa: PLR0913 # pylint: disable=too-many-positional-arguments
self,
method: str,
path: str,
json: dict[str, Any] | None = None,
data: dict[str, Any] | aiohttp.FormData | None = None,
form: dict[str, Any] | None = None,
params: dict[str, Any] | None = None,
**kwargs: Any,
) -> AsyncGenerator[aiohttp.ClientResponse]:
"""Send a request to the Paperless api and return the `aiohttp.ClientResponse`.
This method provides a little interface for utilizing `aiohttp.FormData`.
`method`: A http method: get, post, patch, put, delete, head, options
`path`: A path to the endpoint or a string url.
`json`: A dict containing the json data.
`data`: A dict containing the data to send in the request body.
`form`: A dict with form data, which gets converted to `aiohttp.FormData`
and replaces `data`.
`params`: A dict with query parameters.
`kwargs`: Optional attributes for the `aiohttp.ClientSession.request` method.
"""
if self._session is None:
self._session = aiohttp.ClientSession()
# add headers
headers = {
"Accept": f"application/json; version={self._request_api_version}",
}
if self._token:
headers["Authorization"] = f"Token {self._token}"
# Merge with any user-defined headers (optional)
if "headers" in kwargs:
kwargs["headers"].update(headers)
else:
kwargs["headers"] = headers
# add request args
kwargs.update(self._request_args)
# overwrite data with a form, when there is a form payload
if isinstance(form, dict):
data = self._process_form(form)
# add base path
url = f"{self._base_url}{path}" if not path.startswith("http") else path
try:
res = await self._session.request(
method=method,
url=url,
json=json,
data=data,
params=params,
**kwargs,
)
self.logger.debug("%s (%d): %s", method.upper(), res.status, res.url)
except aiohttp.ClientConnectionError as err:
raise PaperlessConnectionError from err
# error handling for 401 and 403 codes
if res.status == 401:
try:
error_data = await res.json()
detail = error_data.get("detail", "")
except JSONDecodeError:
detail = ""
if "inactive" in detail.lower() or "deleted" in detail.lower():
raise PaperlessInactiveOrDeletedError(res)
raise PaperlessInvalidTokenError(res)
if res.status == 403:
raise PaperlessForbiddenError(res)
yield res
async def request_json(
self,
method: str,
endpoint: str,
**kwargs: Any,
) -> Any:
"""Make a request to the api and parse response json to dict."""
async with self.request(method, endpoint, **kwargs) as res:
if res.content_type != "application/json":
raise BadJsonResponseError(res)
try:
payload = await res.json()
except ValueError:
raise BadJsonResponseError(res) from None
if res.status == 400:
raise JsonResponseWithError(payload)
res.raise_for_status()
return payload
paperless-api-5.1.0/pypaperless/const.py 0000664 0000000 0000000 00000010030 15053074171 0020326 0 ustar 00root root 0000000 0000000 """PyPaperless constants."""
from __future__ import annotations
from enum import StrEnum
API_VERSION = 9
CONFIG = "config"
CONSUMPTION_TEMPLATES = "consumption_templates"
CORRESPONDENTS = "correspondents"
CUSTOM_FIELDS = "custom_fields"
DOCUMENTS = "documents"
DOCUMENT_TYPES = "document_types"
GROUPS = "groups"
LOGS = "logs"
MAIL_ACCOUNTS = "mail_accounts"
MAIL_RULES = "mail_rules"
SAVED_VIEWS = "saved_views"
SHARE_LINKS = "share_links"
STATISTICS = "statistics"
REMOTE_VERSION = "remote_version"
STATUS = "status"
STORAGE_PATHS = "storage_paths"
TAGS = "tags"
TASKS = "tasks"
USERS = "users"
WORKFLOW_ACTIONS = "workflow_actions"
WORKFLOWS = "workflows"
WORKFLOW_TRIGGERS = "workflow_triggers"
UNKNOWN = "unknown"
API_PATH = {
"index": "/api/schema/",
"token": "/api/token/",
f"{CONFIG}": f"/api/{CONFIG}/",
f"{CONFIG}_single": f"/api/{CONFIG}/{{pk}}/",
f"{CORRESPONDENTS}": f"/api/{CORRESPONDENTS}/",
f"{CORRESPONDENTS}_single": f"/api/{CORRESPONDENTS}/{{pk}}/",
f"{CUSTOM_FIELDS}": f"/api/{CUSTOM_FIELDS}/",
f"{CUSTOM_FIELDS}_single": f"/api/{CUSTOM_FIELDS}/{{pk}}/",
f"{DOCUMENTS}": f"/api/{DOCUMENTS}/",
f"{DOCUMENTS}_download": f"/api/{DOCUMENTS}/{{pk}}/download/",
f"{DOCUMENTS}_meta": f"/api/{DOCUMENTS}/{{pk}}/metadata/",
f"{DOCUMENTS}_next_asn": f"/api/{DOCUMENTS}/next_asn/",
f"{DOCUMENTS}_notes": f"/api/{DOCUMENTS}/{{pk}}/notes/",
f"{DOCUMENTS}_preview": f"/api/{DOCUMENTS}/{{pk}}/preview/",
f"{DOCUMENTS}_thumbnail": f"/api/{DOCUMENTS}/{{pk}}/thumb/",
f"{DOCUMENTS}_post": f"/api/{DOCUMENTS}/post_document/",
f"{DOCUMENTS}_single": f"/api/{DOCUMENTS}/{{pk}}/",
f"{DOCUMENTS}_suggestions": f"/api/{DOCUMENTS}/{{pk}}/suggestions/",
f"{DOCUMENT_TYPES}": f"/api/{DOCUMENT_TYPES}/",
f"{DOCUMENT_TYPES}_single": f"/api/{DOCUMENT_TYPES}/{{pk}}/",
f"{GROUPS}": f"/api/{GROUPS}/",
f"{GROUPS}_single": f"/api/{GROUPS}/{{pk}}/",
f"{MAIL_ACCOUNTS}": f"/api/{MAIL_ACCOUNTS}/",
f"{MAIL_ACCOUNTS}_single": f"/api/{MAIL_ACCOUNTS}/{{pk}}/",
f"{MAIL_RULES}": f"/api/{MAIL_RULES}/",
f"{MAIL_RULES}_single": f"/api/{MAIL_RULES}/{{pk}}/",
f"{SAVED_VIEWS}": f"/api/{SAVED_VIEWS}/",
f"{SAVED_VIEWS}_single": f"/api/{SAVED_VIEWS}/{{pk}}/",
f"{SHARE_LINKS}": f"/api/{SHARE_LINKS}/",
f"{SHARE_LINKS}_single": f"/api/{SHARE_LINKS}/{{pk}}/",
f"{STATISTICS}": f"/api/{STATISTICS}/",
f"{REMOTE_VERSION}": f"/api/{REMOTE_VERSION}/",
f"{STATUS}": f"/api/{STATUS}/",
f"{STORAGE_PATHS}": f"/api/{STORAGE_PATHS}/",
f"{STORAGE_PATHS}_single": f"/api/{STORAGE_PATHS}/{{pk}}/",
f"{TAGS}": f"/api/{TAGS}/",
f"{TAGS}_single": f"/api/{TAGS}/{{pk}}/",
f"{TASKS}": f"/api/{TASKS}/",
f"{TASKS}_single": f"/api/{TASKS}/{{pk}}/",
f"{USERS}": f"/api/{USERS}/",
f"{USERS}_single": f"/api/{USERS}/{{pk}}/",
f"{WORKFLOWS}": f"/api/{WORKFLOWS}/",
f"{WORKFLOWS}_single": f"/api/{WORKFLOWS}/{{pk}}/",
f"{WORKFLOW_ACTIONS}": f"/api/{WORKFLOW_ACTIONS}/",
f"{WORKFLOW_ACTIONS}_single": f"/api/{WORKFLOW_ACTIONS}/{{pk}}/",
f"{WORKFLOW_TRIGGERS}": f"/api/{WORKFLOW_TRIGGERS}/",
f"{WORKFLOW_TRIGGERS}_single": f"/api/{WORKFLOW_TRIGGERS}/{{pk}}/",
}
class PaperlessResource(StrEnum):
"""Represent paths of api endpoints."""
CONFIG = CONFIG
CONSUMPTION_TEMPLATES = CONSUMPTION_TEMPLATES
CORRESPONDENTS = CORRESPONDENTS
CUSTOM_FIELDS = CUSTOM_FIELDS
DOCUMENTS = DOCUMENTS
DOCUMENT_TYPES = DOCUMENT_TYPES
GROUPS = GROUPS
LOGS = LOGS
MAIL_ACCOUNTS = MAIL_ACCOUNTS
MAIL_RULES = MAIL_RULES
SAVED_VIEWS = SAVED_VIEWS
SHARE_LINKS = SHARE_LINKS
STATISTICS = STATISTICS
REMOTE_VERSION = REMOTE_VERSION
STATUS = STATUS
STORAGE_PATHS = STORAGE_PATHS
TAGS = TAGS
TASKS = TASKS
USERS = USERS
WORKFLOWS = WORKFLOWS
WORKFLOW_ACTIONS = WORKFLOW_ACTIONS
WORKFLOW_TRIGGERS = WORKFLOW_TRIGGERS
UNKNOWN = UNKNOWN
@classmethod
def _missing_(cls: type[PaperlessResource], *_: object) -> PaperlessResource:
"""Set default member on unknown value."""
return cls.UNKNOWN
paperless-api-5.1.0/pypaperless/exceptions.py 0000664 0000000 0000000 00000005676 15053074171 0021405 0 ustar 00root root 0000000 0000000 """PyPaperless exceptions."""
from typing import Any
class PaperlessError(Exception):
"""Base exception for PyPaperless."""
# Sessions and requests
class InitializationError(PaperlessError):
"""Raise when initializing a `Paperless` instance without valid url or token."""
class PaperlessConnectionError(InitializationError, PaperlessError):
"""Raise when connection to Paperless is not possible."""
class PaperlessAuthError(InitializationError, PaperlessError):
"""Raise when response is 401 code."""
class PaperlessInvalidTokenError(PaperlessAuthError):
"""Raise when response is 401 due invalid access token."""
class PaperlessInactiveOrDeletedError(PaperlessAuthError):
"""Raise when response is 401 code due user is inactive or deleted."""
class PaperlessForbiddenError(InitializationError, PaperlessError):
"""Raise when response is 403 code."""
class BadJsonResponseError(PaperlessError):
"""Raise when response is no valid json."""
class JsonResponseWithError(PaperlessError):
"""Raise when Paperless accepted the request, but responded with an error payload."""
def __init__(self, payload: Any) -> None:
"""Initialize a `JsonResponseWithError` instance."""
def _parse_payload(payload: Any, key: list[str] | None = None) -> tuple[list[str], str]:
"""Parse first suitable error from payload."""
if key is None:
key = []
if isinstance(payload, list):
return _parse_payload(payload.pop(0), key)
if isinstance(payload, dict):
if "error" in payload:
key.append("error")
return _parse_payload(payload["error"], key)
new_key = next(iter(payload))
key.append(new_key)
return _parse_payload(payload[new_key], key)
return key, payload
key, message = _parse_payload(payload)
if len(key) == 0:
key.append("error")
key_chain = " -> ".join(key)
super().__init__(f"Paperless [{key_chain}]: {message}")
# Models
class AsnRequestError(PaperlessError):
"""Raise when getting an error during requesting the next asn."""
class DraftFieldRequiredError(PaperlessError):
"""Raise when trying to save models with missing required fields."""
class DraftNotSupportedError(PaperlessError):
"""Raise when trying to draft unsupported models."""
class ItemNotFoundError(PaperlessError):
"""Raise when trying to access non-existing items in PaperlessModelData classes."""
class PrimaryKeyRequiredError(PaperlessError):
"""Raise when trying to access model data without supplying a pk."""
# Tasks
class TaskNotFoundError(PaperlessError):
"""Raise when trying to access a task by non-existing uuid."""
def __init__(self, task_id: str) -> None:
"""Initialize a `TaskNotFound` instance."""
super().__init__(f"Task with UUID {task_id} not found.")
paperless-api-5.1.0/pypaperless/helpers.py 0000664 0000000 0000000 00000002005 15053074171 0020645 0 ustar 00root root 0000000 0000000 """PyPaperless helpers."""
# pylint: disable=unused-import
from .models.base import HelperBase # noqa: F401
from .models.classifiers import ( # noqa: F401
CorrespondentHelper,
DocumentTypeHelper,
StoragePathHelper,
TagHelper,
)
from .models.config import ConfigHelper # noqa: F401
from .models.custom_fields import CustomFieldHelper # noqa: F401
from .models.documents import DocumentHelper, DocumentMetaHelper, DocumentNoteHelper # noqa: F401
from .models.mails import MailAccountHelper, MailRuleHelper # noqa: F401
from .models.permissions import GroupHelper, UserHelper # noqa: F401
from .models.remote_version import RemoteVersionHelper # noqa: F401
from .models.saved_views import SavedViewHelper # noqa: F401
from .models.share_links import ShareLinkHelper # noqa: F401
from .models.statistics import StatisticHelper # noqa: F401
from .models.status import StatusHelper # noqa: F401
from .models.tasks import TaskHelper # noqa: F401
from .models.workflows import WorkflowHelper # noqa: F401
paperless-api-5.1.0/pypaperless/models/ 0000775 0000000 0000000 00000000000 15053074171 0020117 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pypaperless/models/__init__.py 0000664 0000000 0000000 00000002536 15053074171 0022236 0 ustar 00root root 0000000 0000000 """PyPaperless models."""
from .classifiers import (
Correspondent,
CorrespondentDraft,
DocumentType,
DocumentTypeDraft,
StoragePath,
StoragePathDraft,
Tag,
TagDraft,
)
from .config import Config
from .custom_fields import CustomField, CustomFieldDraft
from .documents import (
Document,
DocumentDraft,
DocumentMeta,
DocumentNote,
DocumentNoteDraft,
)
from .mails import MailAccount, MailRule
from .pages import Page
from .permissions import Group, User
from .remote_version import RemoteVersion
from .saved_views import SavedView
from .share_links import ShareLink, ShareLinkDraft
from .statistics import Statistic
from .status import Status
from .tasks import Task
from .workflows import Workflow, WorkflowAction, WorkflowTrigger
__all__ = (
"Config",
"Correspondent",
"CorrespondentDraft",
"CustomField",
"CustomFieldDraft",
"Document",
"DocumentDraft",
"DocumentMeta",
"DocumentNote",
"DocumentNoteDraft",
"DocumentType",
"DocumentTypeDraft",
"Group",
"MailAccount",
"MailRule",
"Page",
"RemoteVersion",
"SavedView",
"ShareLink",
"ShareLinkDraft",
"Statistic",
"Status",
"StoragePath",
"StoragePathDraft",
"Tag",
"TagDraft",
"Task",
"User",
"Workflow",
"WorkflowAction",
"WorkflowTrigger",
)
paperless-api-5.1.0/pypaperless/models/base.py 0000664 0000000 0000000 00000007331 15053074171 0021407 0 ustar 00root root 0000000 0000000 """Provide base classes."""
from abc import ABC, abstractmethod
from dataclasses import Field, dataclass, fields
from typing import TYPE_CHECKING, Any, Protocol, Self, TypeVar, final
from pypaperless.const import API_PATH, PaperlessResource
from pypaperless.models.utils import dict_value_to_object
if TYPE_CHECKING:
from pypaperless import Paperless
ResourceT = TypeVar("ResourceT", bound="PaperlessModel")
class PaperlessBase:
"""Superclass for all classes in PyPaperless."""
_api_path = API_PATH["index"]
def __init__(self, api: "Paperless") -> None:
"""Initialize a `PaperlessBase` instance."""
self._api = api
class HelperProtocol[ResourceT](Protocol):
"""Protocol for any `HelperBase` instances and its ancestors."""
_api: "Paperless"
_api_path: str
_resource: PaperlessResource
_resource_cls: type[ResourceT]
class HelperBase(PaperlessBase):
"""Base class for all helpers in PyPaperless."""
_resource: PaperlessResource
@dataclass(init=False)
class PaperlessModelProtocol(Protocol):
"""Protocol for any `PaperlessBase` instances and its ancestors."""
_api: "Paperless"
_api_path: str
_data: dict[str, Any]
_fetched: bool
_params: dict[str, Any]
# fmt: off
def _get_dataclass_fields(self) -> list[Field]: ...
def _set_dataclass_fields(self) -> None: ...
# fmt: on
@dataclass(init=False)
class PaperlessModel(PaperlessBase):
"""Base class for all models in PyPaperless."""
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `PaperlessModel` instance."""
super().__init__(api)
self._data = {}
self._data.update(data)
self._fetched = False
self._params: dict[str, Any] = {}
@final
@classmethod
def create_with_data(
cls,
api: "Paperless",
data: dict[str, Any],
*,
fetched: bool = False,
) -> Self:
"""Return a new instance of `cls` from `data`.
Primarily used by class factories to create new model instances.
Example: `document = Document.create_with_data(...)`
"""
item = cls(api, data=data)
item._fetched = fetched
if fetched:
item._set_dataclass_fields()
return item
@final
def _get_dataclass_fields(self) -> list[Field]:
"""Get the dataclass fields."""
return [
field
for field in fields(self)
if (not field.name.startswith("_") or field.name == "__search_hit__")
]
@final
def _set_dataclass_fields(self) -> None:
"""Set the dataclass fields from `self._data`."""
for field in self._get_dataclass_fields():
value = dict_value_to_object(
f"{self.__class__.__name__}.{field.name}",
self._data.get(field.name),
field.type,
field.default,
self._api,
)
setattr(self, field.name, value)
@property
def is_fetched(self) -> bool:
"""Return whether the `model data` is fetched or not."""
return self._fetched
async def load(self) -> None:
"""Get `model data` from DRF."""
data = await self._api.request_json("get", self._api_path, params=self._params)
self._data.update(data)
self._set_dataclass_fields()
self._fetched = True
class PaperlessModelData(ABC):
"""Base class for all custom data types in PyPaperless."""
@classmethod
@abstractmethod
def unserialize(cls, api: "Paperless", data: Any) -> Self:
"""Return a new instance of `cls` from `data`."""
@abstractmethod
def serialize(self) -> Any:
"""Serialize the class data."""
paperless-api-5.1.0/pypaperless/models/classifiers.py 0000664 0000000 0000000 00000015073 15053074171 0023006 0 ustar 00root root 0000000 0000000 """Provide `Correspondent`, `DocumentType`, `StoragePath` and `Tag` related models and helpers."""
import datetime
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .mixins import helpers, models
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class Correspondent(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableMixin,
models.UpdatableMixin,
models.DeletableMixin,
):
"""Represent a Paperless `Correspondent`."""
_api_path = API_PATH["correspondents_single"]
id: int | None = None
slug: str | None = None
name: str | None = None
document_count: int | None = None
last_correspondence: datetime.date | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Correspondent` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class CorrespondentDraft(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableDraftMixin,
models.CreatableMixin,
):
"""Represent a new `Correspondent`, which is not yet stored in Paperless."""
_api_path = API_PATH["correspondents"]
_create_required_fields = {
"name",
"match",
"matching_algorithm",
"is_insensitive",
}
name: str | None = None
@dataclass(init=False)
class DocumentType(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableMixin,
models.UpdatableMixin,
models.DeletableMixin,
):
"""Represent a Paperless `DocumentType`."""
_api_path = API_PATH["document_types_single"]
id: int | None = None
slug: str | None = None
name: str | None = None
document_count: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `DocumentType` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class DocumentTypeDraft(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableDraftMixin,
models.CreatableMixin,
):
"""Represent a new `DocumentType`, which is not yet stored in Paperless."""
_api_path = API_PATH["document_types"]
_create_required_fields = {
"name",
"match",
"matching_algorithm",
"is_insensitive",
}
name: str | None = None
owner: int | None = None
@dataclass(init=False)
class StoragePath(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableMixin,
models.UpdatableMixin,
models.DeletableMixin,
):
"""Represent a Paperless `StoragePath`."""
_api_path = API_PATH["storage_paths_single"]
id: int | None = None
slug: str | None = None
name: str | None = None
path: str | None = None
document_count: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `StoragePath` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class StoragePathDraft(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableDraftMixin,
models.CreatableMixin,
):
"""Represent a new `StoragePath`, which is not yet stored in Paperless."""
_api_path = API_PATH["storage_paths"]
_create_required_fields = {
"name",
"path",
"match",
"matching_algorithm",
"is_insensitive",
}
name: str | None = None
path: str | None = None
owner: int | None = None
@dataclass(init=False)
class Tag(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableMixin,
models.UpdatableMixin,
models.DeletableMixin,
):
"""Represent a Paperless `Tag`."""
_api_path = API_PATH["tags_single"]
id: int | None = None
slug: str | None = None
name: str | None = None
color: str | None = None
text_color: str | None = None
is_inbox_tag: bool | None = None
document_count: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Tag` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class TagDraft(
PaperlessModel,
models.MatchingFieldsMixin,
models.SecurableDraftMixin,
models.CreatableMixin,
):
"""Represent a new `Tag`, which is not yet stored in Paperless."""
_api_path = API_PATH["tags"]
_create_required_fields = {
"name",
"color",
"is_inbox_tag",
"match",
"matching_algorithm",
"is_insensitive",
}
name: str | None = None
color: str | None = None
text_color: str | None = None
is_inbox_tag: bool | None = None
owner: int | None = None
class CorrespondentHelper(
HelperBase,
helpers.SecurableMixin,
helpers.CallableMixin[Correspondent],
helpers.DraftableMixin[CorrespondentDraft],
helpers.IterableMixin[Correspondent],
):
"""Represent a factory for Paperless `Correspondent` models."""
_api_path = API_PATH["correspondents"]
_resource = PaperlessResource.CORRESPONDENTS
_draft_cls = CorrespondentDraft
_resource_cls = Correspondent
class DocumentTypeHelper(
HelperBase,
helpers.SecurableMixin,
helpers.CallableMixin[DocumentType],
helpers.DraftableMixin[DocumentTypeDraft],
helpers.IterableMixin[DocumentType],
):
"""Represent a factory for Paperless `DocumentType` models."""
_api_path = API_PATH["document_types"]
_resource = PaperlessResource.DOCUMENT_TYPES
_draft_cls = DocumentTypeDraft
_resource_cls = DocumentType
class StoragePathHelper(
HelperBase,
helpers.SecurableMixin,
helpers.CallableMixin[StoragePath],
helpers.DraftableMixin[StoragePathDraft],
helpers.IterableMixin[StoragePath],
):
"""Represent a factory for Paperless `StoragePath` models."""
_api_path = API_PATH["storage_paths"]
_resource = PaperlessResource.STORAGE_PATHS
_draft_cls = StoragePathDraft
_resource_cls = StoragePath
class TagHelper(
HelperBase,
helpers.SecurableMixin,
helpers.CallableMixin[Tag],
helpers.DraftableMixin[TagDraft],
helpers.IterableMixin[Tag],
):
"""Represent a factory for Paperless `Tag` models."""
_api_path = API_PATH["tags"]
_resource = PaperlessResource.TAGS
_draft_cls = TagDraft
_resource_cls = Tag
paperless-api-5.1.0/pypaperless/models/common.py 0000664 0000000 0000000 00000027122 15053074171 0021765 0 ustar 00root root 0000000 0000000 """PyPaperless common types."""
import contextlib
import datetime
import re
from dataclasses import dataclass, field
from enum import Enum, StrEnum
from typing import TYPE_CHECKING, Any, TypedDict, TypeVar
if TYPE_CHECKING:
from pypaperless import Paperless
from .classifiers import Correspondent, DocumentType, StoragePath, Tag
from .custom_fields import CustomField
# custom_fields
class CustomFieldExtraDataSelectOptions(TypedDict):
"""Represent the `extra_data.select_options` field of a `CustomField`."""
id: str | None
label: str | None
class CustomFieldExtraData(TypedDict):
"""Represent the `extra_data` field of a `CustomField`."""
default_currency: str | None
select_options: list[CustomFieldExtraDataSelectOptions | None]
class CustomFieldType(Enum):
"""Represent a subtype of `CustomField`."""
STRING = "string"
URL = "url"
DATE = "date"
BOOLEAN = "boolean"
INTEGER = "integer"
FLOAT = "float"
MONETARY = "monetary"
DOCUMENT_LINK = "documentlink"
SELECT = "select"
UNKNOWN = "unknown"
@classmethod
def _missing_(cls: type, *_: object) -> "CustomFieldType":
"""Set default member on unknown value."""
return CustomFieldType.UNKNOWN
# documents
@dataclass(kw_only=True)
class CustomFieldValue:
"""Represent a subtype of `CustomField`."""
field: int | None = None
value: Any | None = None
name: str | None = None
data_type: CustomFieldType | None = None
extra_data: CustomFieldExtraData | None = None
CustomFieldValueT = TypeVar("CustomFieldValueT", bound=CustomFieldValue)
@dataclass(kw_only=True)
class CustomFieldBooleanValue(CustomFieldValue):
"""Represent a boolean `CustomFieldValue`."""
value: bool | None = None
@dataclass(kw_only=True)
class CustomFieldDateValue(CustomFieldValue):
"""Represent a date `CustomFieldValue`."""
value: datetime.date | str | None = None
def __post_init__(self) -> None:
"""Convert the value to a datetime."""
if isinstance(self.value, str):
with contextlib.suppress(ValueError):
dt = datetime.datetime.fromisoformat(self.value)
self.value = dt.date()
@dataclass(kw_only=True)
class CustomFieldDocumentLinkValue(CustomFieldValue):
"""Represent a document link `CustomFieldValue`."""
value: list[int] | None = None
@dataclass(kw_only=True)
class CustomFieldFloatValue(CustomFieldValue):
"""Represent a float `CustomFieldValue`."""
value: float | None = None
@dataclass(kw_only=True)
class CustomFieldIntegerValue(CustomFieldValue):
"""Represent an integer `CustomFieldValue`."""
value: int | None = None
@dataclass(kw_only=True)
class CustomFieldMonetaryValue(CustomFieldValue):
"""Represent a monetary `CustomFieldValue`."""
value: str | None = None
@property
def currency(self) -> str | None:
"""Return the currency of the `value` field."""
if self.value and (match := re.match(r"^([a-zA-Z]{3})", self.value)):
return match.group(1) if match else self.value
if self.extra_data and (default_currency := self.extra_data.get("default_currency", None)):
return default_currency
return ""
@currency.setter
def currency(self, new_currency: str) -> None:
"""Override the currency of the field."""
value = self.value or ""
value = re.sub(r"^[a-zA-Z]{3}", "", value)
if new_currency and re.match(r"^[A-Z]{3}$", new_currency):
self.value = f"{new_currency}{value}"
else:
self.value = value
@property
def amount(self) -> float | None:
"""Return the amount without currentcy of the `value` field."""
if self.value:
numeric = re.sub(r"[^\d.]", "", self.value)
return float(numeric)
return None
@amount.setter
def amount(self, new_amount: float) -> None:
"""Set a new amount and construct the internal needed value."""
self.value = f"{self.currency}{new_amount:.2f}"
@dataclass(kw_only=True)
class CustomFieldSelectValue(CustomFieldValue):
"""Represent a select `CustomFieldValue`."""
value: int | str | None = None
@property
def labels(self) -> list[CustomFieldExtraDataSelectOptions | None]:
"""Return the list of labels of the `CustomField`."""
if not self.extra_data:
return []
return self.extra_data["select_options"]
@property
def label(self) -> str | None:
"""Return the label for `value` or fall back to `None`."""
for opt in self.labels:
if opt and opt["id"] == self.value:
return opt["label"]
return None
@dataclass(kw_only=True)
class CustomFieldStringValue(CustomFieldValue):
"""Represent a string `CustomFieldValue`."""
value: str | None = None
@dataclass(kw_only=True)
class CustomFieldURLValue(CustomFieldValue):
"""Represent an url `CustomFieldValue`."""
value: str | None = None
CUSTOM_FIELD_TYPE_VALUE_MAP: dict[CustomFieldType, type[CustomFieldValue]] = {
CustomFieldType.BOOLEAN: CustomFieldBooleanValue,
CustomFieldType.DATE: CustomFieldDateValue,
CustomFieldType.DOCUMENT_LINK: CustomFieldDocumentLinkValue,
CustomFieldType.FLOAT: CustomFieldFloatValue,
CustomFieldType.INTEGER: CustomFieldIntegerValue,
CustomFieldType.MONETARY: CustomFieldMonetaryValue,
CustomFieldType.SELECT: CustomFieldSelectValue,
CustomFieldType.STRING: CustomFieldStringValue,
CustomFieldType.URL: CustomFieldURLValue,
}
# documents
@dataclass(kw_only=True)
class DocumentMetadataType:
"""Represent a subtype of `DocumentMeta`."""
namespace: str | None = None
prefix: str | None = None
key: str | None = None
value: str | None = None
# documents
@dataclass(kw_only=True)
class DocumentSearchHitType:
"""Represent a subtype of `Document`."""
score: float | None = None
highlights: str | None = None
note_highlights: str | None = None
rank: int | None = None
# api
@dataclass(kw_only=True)
class MasterDataInstance:
"""Represent a `MasterDataInstance`."""
api: "Paperless"
is_initialized: bool = False
correspondents: list["Correspondent"] = field(default_factory=list)
custom_fields: list["CustomField"] = field(default_factory=list)
document_types: list["DocumentType"] = field(default_factory=list)
storage_paths: list["StoragePath"] = field(default_factory=list)
tags: list["Tag"] = field(default_factory=list)
# mixins/models/data_fields, used for classifiers
class MatchingAlgorithmType(Enum):
"""Represent a subtype of `Correspondent`, `DocumentType`, `StoragePath` and `Tag`."""
NONE = 0
ANY = 1
ALL = 2
LITERAL = 3
REGEX = 4
FUZZY = 5
AUTO = 6
UNKNOWN = -1
@classmethod
def _missing_(cls: type, *_: object) -> "MatchingAlgorithmType":
"""Set default member on unknown value."""
return MatchingAlgorithmType.UNKNOWN
# api
@dataclass(kw_only=True)
class PaperlessCache:
"""Represent a Paperless cache object."""
custom_fields: dict[int, "CustomField"] | None = None
# mixins/models/securable
@dataclass(kw_only=True)
class PermissionSetType:
"""Represent a Paperless permission set."""
users: list[int] = field(default_factory=list)
groups: list[int] = field(default_factory=list)
# mixins/models/securable
@dataclass(kw_only=True)
class PermissionTableType:
"""Represent a Paperless permissions type."""
view: PermissionSetType = field(default_factory=PermissionSetType)
change: PermissionSetType = field(default_factory=PermissionSetType)
# documents
class RetrieveFileMode(StrEnum):
"""Represent a subtype of `DownloadedDocument`."""
DOWNLOAD = "download"
PREVIEW = "preview"
THUMBNAIL = "thumb"
# saved_views
@dataclass(kw_only=True)
class SavedViewFilterRuleType:
"""Represent a subtype of `SavedView`."""
rule_type: int | None = None
value: str | None = None
# share_links
class ShareLinkFileVersionType(Enum):
"""Represent a subtype of `ShareLink`."""
ARCHIVE = "archive"
ORIGINAL = "original"
UNKNOWN = "unknown"
@classmethod
def _missing_(cls: type, *_: object) -> "ShareLinkFileVersionType":
"""Set default member on unknown value."""
return ShareLinkFileVersionType.UNKNOWN
# statistics
@dataclass(kw_only=True)
class StatisticDocumentFileTypeCount:
"""Represent a Paperless statistics file type count."""
mime_type: str | None = None
mime_type_count: int | None = None
# status
class StatusType(Enum):
"""Represent a subtype of `Status`."""
OK = "OK"
ERROR = "ERROR"
WARNING = "WARNING"
UNKNOWN = "UNKNOWN"
@classmethod
def _missing_(cls: type, *_: object) -> "StatusType":
"""Set default member on unknown value."""
return StatusType.UNKNOWN
# status
@dataclass(kw_only=True)
class StatusDatabaseMigrationStatusType:
"""Represent a subtype of `StatusDatabaseType`."""
latest_migration: str | None = None
unapplied_migrations: list[str] = field(default_factory=list)
# status
@dataclass(kw_only=True)
class StatusDatabaseType:
"""Represent a subtype of `Status`."""
type: str | None = None
url: str | None = None
status: StatusType | None = None
error: str | None = None
migration_status: StatusDatabaseMigrationStatusType | None = None
# status
@dataclass(kw_only=True)
class StatusStorageType:
"""Represent a subtype of `Status`."""
total: int | None = None
available: int | None = None
# status
@dataclass(kw_only=True)
class StatusTasksType:
"""Represent a subtype of `Status`."""
redis_url: str | None = None
redis_status: StatusType | None = None
redis_error: str | None = None
celery_status: StatusType | None = None
celery_url: str | None = None
celery_error: str | None = None
index_status: StatusType | None = None
index_last_modified: datetime.datetime | None = None
index_error: str | None = None
classifier_status: StatusType | None = None
classifier_last_trained: datetime.datetime | None = None
classifier_error: str | None = None
sanity_check_status: StatusType | None = None
sanity_check_last_run: datetime.datetime | None = None
sanity_check_error: str | None = None
# tasks
class TaskStatusType(Enum):
"""Represent a subtype of `Task`."""
PENDING = "PENDING"
STARTED = "STARTED"
SUCCESS = "SUCCESS"
FAILURE = "FAILURE"
UNKNOWN = "UNKNOWN"
@classmethod
def _missing_(cls: type, *_: object) -> "TaskStatusType":
"""Set default member on unknown value."""
return TaskStatusType.UNKNOWN
# workflows
class WorkflowActionType(Enum):
"""Represent a subtype of `Workflow`."""
ASSIGNMENT = 1
UNKNOWN = -1
@classmethod
def _missing_(cls: type, *_: object) -> "WorkflowActionType":
"""Set default member on unknown value."""
return WorkflowActionType.UNKNOWN
# workflows
class WorkflowTriggerType(Enum):
"""Represent a subtype of `Workflow`."""
CONSUMPTION = 1
DOCUMENT_ADDED = 2
DOCUMENT_UPDATED = 3
UNKNOWN = -1
@classmethod
def _missing_(cls: type, *_: object) -> "WorkflowTriggerType":
"""Set default member on unknown value."""
return WorkflowTriggerType.UNKNOWN
# workflows
class WorkflowTriggerSourceType(Enum):
"""Represent a subtype of `Workflow`."""
CONSUME_FOLDER = 1
API_UPLOAD = 2
MAIL_FETCH = 3
UNKNOWN = -1
@classmethod
def _missing_(cls: type, *_: object) -> "WorkflowTriggerSourceType":
"""Set default member on unknown value."""
return WorkflowTriggerSourceType.UNKNOWN
paperless-api-5.1.0/pypaperless/models/config.py 0000664 0000000 0000000 00000003643 15053074171 0021744 0 ustar 00root root 0000000 0000000 """Provide `Config` related models and helpers."""
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .mixins import helpers
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class Config(PaperlessModel):
"""Represent a Paperless `Config`."""
_api_path = API_PATH["config_single"]
id: int | None = None
user_args: str | None = None
output_type: str | None = None
pages: int | None = None
language: str | None = None
mode: str | None = None
skip_archive_file: str | None = None
image_dpi: int | None = None
unpaper_clean: str | None = None
deskew: bool | None = None
rotate_pages: bool | None = None
rotate_pages_threshold: float | None = None
max_image_pixels: float | None = None
color_conversion_strategy: str | None = None
app_title: str | None = None
app_logo: str | None = None
barcode_tag_mapping: dict[str, str] | None = None
barcodes_enabled: bool | None = None
barcode_enable_tiff_support: bool | None = None
barcode_string: str | None = None
barcode_retain_split_pages: bool | None = None
barcode_enable_asn: bool | None = None
barcode_asn_prefix: str | None = None
barcode_upscale: float | None = None
barcode_dpi: int | None = None
barcode_max_pages: int | None = None
barcode_enable_tag: bool | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Config` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
class ConfigHelper(HelperBase, helpers.CallableMixin[Config]):
"""Represent a factory for Paperless `Config` models."""
_api_path = API_PATH["config"]
_resource = PaperlessResource.CONFIG
_resource_cls = Config
paperless-api-5.1.0/pypaperless/models/custom_fields.py 0000664 0000000 0000000 00000005571 15053074171 0023341 0 ustar 00root root 0000000 0000000 """Provide `CustomField` related models and helpers."""
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, overload
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .common import (
CUSTOM_FIELD_TYPE_VALUE_MAP,
CustomFieldExtraData,
CustomFieldType,
CustomFieldValue,
CustomFieldValueT,
)
from .mixins import helpers, models
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class CustomField(
PaperlessModel,
models.UpdatableMixin,
models.DeletableMixin,
):
"""Represent a Paperless `CustomField`."""
_api_path = API_PATH["custom_fields_single"]
id: int
name: str | None = None
data_type: CustomFieldType | None = None
extra_data: CustomFieldExtraData | None = None
document_count: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Document` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@overload
def draft_value(self, value: Any) -> CustomFieldValue: ...
@overload
def draft_value(
self, value: Any, expected_type: type[CustomFieldValueT]
) -> CustomFieldValueT: ...
def draft_value(
self,
value: Any,
expected_type: type[CustomFieldValueT] | None = None, # noqa: ARG002 # pylint: disable=unused-argument
) -> CustomFieldValue | CustomFieldValueT:
"""Draft a new `CustomFieldValue` instance."""
cache = self._api.cache.custom_fields
if cache and self.id in cache:
klass = CUSTOM_FIELD_TYPE_VALUE_MAP.get(
self.data_type or CustomFieldType.UNKNOWN, CustomFieldValue
)
klass_data = {
"field": self.id,
"value": value,
"name": self.name,
"data_type": self.data_type,
"extra_data": self.extra_data,
}
return klass(**klass_data)
return CustomFieldValue(field=self.id, value=value)
@dataclass(init=False)
class CustomFieldDraft(PaperlessModel, models.CreatableMixin):
"""Represent a new Paperless `CustomField`, which is not stored in Paperless."""
_api_path = API_PATH["custom_fields"]
_create_required_fields = {"name", "data_type"}
name: str | None = None
data_type: CustomFieldType | None = None
extra_data: CustomFieldExtraData | None = None
class CustomFieldHelper(
HelperBase,
helpers.CallableMixin[CustomField],
helpers.DraftableMixin[CustomFieldDraft],
helpers.IterableMixin[CustomField],
):
"""Represent a factory for Paperless `CustomField` models."""
_api_path = API_PATH["custom_fields"]
_resource = PaperlessResource.CUSTOM_FIELDS
_draft_cls = CustomFieldDraft
_resource_cls = CustomField
paperless-api-5.1.0/pypaperless/models/documents.py 0000664 0000000 0000000 00000060362 15053074171 0022501 0 ustar 00root root 0000000 0000000 """Provide `Document` related models and helpers."""
import datetime
from collections.abc import AsyncGenerator, Iterator
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Self, cast, overload
from pypaperless.const import API_PATH, PaperlessResource
from pypaperless.exceptions import AsnRequestError, ItemNotFoundError, PrimaryKeyRequiredError
from pypaperless.models.utils import object_to_dict_value
from .base import HelperBase, PaperlessModel, PaperlessModelData
from .common import (
CUSTOM_FIELD_TYPE_VALUE_MAP,
CustomFieldType,
CustomFieldValue,
CustomFieldValueT,
DocumentMetadataType,
DocumentSearchHitType,
RetrieveFileMode,
)
from .custom_fields import CustomField
from .mixins import helpers, models
if TYPE_CHECKING:
from pypaperless import Paperless
class DocumentCustomFieldList(PaperlessModelData):
"""Represent a list of Paperless custom field instances typically on documents."""
def __init__(self, api: "Paperless", data: list[dict[str, Any]]) -> None:
"""Initialize a `DocumentCustomFieldList` instance."""
self._api = api
self._data = data
self._fields: list[CustomFieldValue] = []
cache = api.cache.custom_fields
for item in data:
if cache and (field := cache.get(item["field"], None)):
klass = CUSTOM_FIELD_TYPE_VALUE_MAP.get(
field.data_type or CustomFieldType.UNKNOWN, CustomFieldValue
)
klass_data = {
**item,
"name": field.name,
"data_type": field.data_type,
"extra_data": field.extra_data,
}
self._fields.append(klass(**klass_data))
else:
self._fields.append(CustomFieldValue(**item))
def __contains__(self, field: int | CustomField) -> bool:
"""Check if the given `CustomField` or its id is present in `DocumentCustomFieldList`."""
item_id = field.id if isinstance(field, CustomField) else field
return any(item.field == item_id for item in self._fields)
def __iter__(self) -> Iterator[CustomFieldValue]:
"""Iterate over custom fields.
Example:
-------
```python
for item in document.custom_fields:
# do something
```
"""
yield from self._fields
def __iadd__(self, field: CustomFieldValue) -> Self:
"""Add a new `CustomFieldValue` to a document."""
return self.add(field)
def add(self, field: CustomFieldValue) -> Self:
"""Add a new `CustomFieldValue` to a document."""
self._fields.append(field)
return self
def __isub__(self, field: CustomFieldValue | CustomField | int) -> Self:
"""Remove a `CustomFieldValue` from a document."""
return self.remove(field)
def remove(self, field: CustomFieldValue | CustomField | int) -> Self:
"""Remove a `CustomFieldValue` from a document."""
item_id = (
field.id
if isinstance(field, CustomField)
else field.field
if isinstance(field, CustomFieldValue)
else field
)
self._fields = [field for field in self._fields if field.field != item_id]
return self
@overload
def default(self, field: int | CustomField) -> CustomFieldValue | None: ...
@overload
def default(
self, field: int | CustomField, expected_type: type[CustomFieldValueT]
) -> CustomFieldValueT | None: ...
def default(
self, field: int | CustomField, expected_type: type[CustomFieldValueT] | None = None
) -> CustomFieldValue | CustomFieldValueT | None:
"""Access and return a (typed) `CustomFieldValue`, or `None`."""
try:
value = self.get(field)
except ItemNotFoundError:
return None
if expected_type is not None and not isinstance(value, expected_type):
msg = f"Expected {expected_type.__name__}, got {type(value).__name__}"
raise TypeError(msg)
return value
@overload
def get(self, field: int | CustomField) -> CustomFieldValue: ...
@overload
def get(
self, field: int | CustomField, expected_type: type[CustomFieldValueT]
) -> CustomFieldValueT: ...
def get(
self, field: int | CustomField, expected_type: type[CustomFieldValueT] | None = None
) -> CustomFieldValue | CustomFieldValueT:
"""Access and return a (typed) `CustomFieldValue` from the list."""
item_id = field.id if isinstance(field, CustomField) else field
for item in self._fields:
if item.field == item_id:
if expected_type is not None and not isinstance(item, expected_type):
msg = f"Expected {expected_type.__name__}, got {type(item).__name__}"
raise TypeError(msg)
return item
raise ItemNotFoundError
@classmethod
def unserialize(cls, api: "Paperless", data: list[dict[str, Any]]) -> Self:
"""Return a new instance of `cls` from `data`.
Primarily used by `dict_value_to_object` when instantiating model classes.
"""
return cls(api, data=data)
def serialize(self) -> list[dict[str, Any]]:
"""Serialize the class data."""
return [{"field": field.field, "value": field.value} for field in self._fields]
@dataclass(init=False)
class Document(
PaperlessModel,
models.SecurableMixin,
models.UpdatableMixin,
models.DeletableMixin,
):
"""Represent a Paperless `Document`."""
_api_path = API_PATH["documents_single"]
id: int | None = None
correspondent: int | None = None
document_type: int | None = None
storage_path: int | None = None
title: str | None = None
content: str | None = None
tags: list[int] | None = None
created: datetime.date | None = None
modified: datetime.datetime | None = None
added: datetime.datetime | None = None
deleted_at: datetime.datetime | None = None
archive_serial_number: int | None = None
original_file_name: str | None = None
archived_file_name: str | None = None
is_shared_by_requester: bool | None = None
custom_fields: DocumentCustomFieldList | None = None
page_count: int | None = None
mime_type: str | None = None
__search_hit__: DocumentSearchHitType | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Document` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
self.notes = DocumentNoteHelper(api, data.get("id"))
@property
def created_date(self) -> datetime.date | None:
"""Backward compatibility for the removed `created_date` field."""
return self.created
@property
def has_search_hit(self) -> bool:
"""Return if the document has a search hit attached."""
return self.__search_hit__ is not None
@property
def search_hit(self) -> DocumentSearchHitType | None:
"""Return the document search hit."""
return self.__search_hit__
async def get_download(self, *, original: bool = False) -> "DownloadedDocument":
"""Request and return the `DownloadedDocument` class."""
return await self._api.documents.download(cast("int", self.id), original=original)
async def get_metadata(self) -> "DocumentMeta":
"""Request and return the documents `DocumentMeta` class."""
return await self._api.documents.metadata(cast("int", self.id))
async def get_preview(self, *, original: bool = False) -> "DownloadedDocument":
"""Request and return the `DownloadedDocument` class."""
return await self._api.documents.preview(cast("int", self.id), original=original)
async def get_suggestions(self) -> "DocumentSuggestions":
"""Request and return the `DocumentSuggestions` class."""
return await self._api.documents.suggestions(cast("int", self.id))
async def get_thumbnail(self, *, original: bool = False) -> "DownloadedDocument":
"""Request and return the `DownloadedDocument` class."""
return await self._api.documents.thumbnail(cast("int", self.id), original=original)
@dataclass(init=False)
class DocumentDraft(PaperlessModel, models.CreatableMixin):
"""Represent a new Paperless `Document`, which is not stored in Paperless."""
_api_path = API_PATH["documents_post"]
_create_required_fields = {"document"}
document: bytes | None = None
filename: str | None = None
title: str | None = None
created: datetime.datetime | None = None
correspondent: int | None = None
document_type: int | None = None
storage_path: int | None = None
tags: int | list[int] | None = None
archive_serial_number: int | None = None
custom_fields: list[int] | None = None
def _serialize(self) -> dict[str, Any]:
"""Serialize."""
data = {
"form": {
field.name: object_to_dict_value(getattr(self, field.name))
for field in self._get_dataclass_fields()
if field.name not in {"document", "filename"}
}
}
data["form"].update(
{
"document": (
(self.document, self.filename) if self.filename is not None else self.document
)
}
)
return data
@dataclass(init=False)
class DocumentNote(PaperlessModel):
"""Represent a Paperless `DocumentNote`."""
_api_path = API_PATH["documents_notes"]
id: int | None = None
note: str | None = None
created: datetime.datetime | None = None
document: int | None = None
user: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `DocumentNote` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("document"))
async def delete(self) -> bool:
"""Delete a `resource item` from DRF. There is no point of return.
Return `True` when deletion was successful, `False` otherwise.
Example:
-------
```python
# request document notes
notes = await paperless.documents.notes(42)
for note in notes:
if await note.delete():
print("Successfully deleted the note!")
```
"""
params = {
"id": self.id,
}
async with self._api.request("delete", self._api_path, params=params) as res:
return res.status in {200, 204} # backward compatibility
@dataclass(kw_only=True)
class DocumentNoteDraft(PaperlessModel, models.CreatableMixin):
"""Represent a new Paperless `DocumentNote`, which is not stored in Paperless."""
_api_path = API_PATH["documents_notes"]
_create_required_fields = {"note", "document"}
note: str | None = None
document: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `DocumentNote` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("document"))
@dataclass(init=False)
class DocumentMeta(PaperlessModel):
"""Represent a Paperless `Document`s metadata."""
_api_path = API_PATH["documents_meta"]
id: int | None = None
original_checksum: str | None = None
original_size: int | None = None
original_mime_type: str | None = None
media_filename: str | None = None
has_archive_version: bool | None = None
original_metadata: list[DocumentMetadataType] | None = None
archive_checksum: str | None = None
archive_media_filename: str | None = None
original_filename: str | None = None
lang: str | None = None
archive_size: int | None = None
archive_metadata: list[DocumentMetadataType] | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `DocumentMeta` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class DownloadedDocument(PaperlessModel):
"""Represent a Paperless `Document`s downloaded file."""
_api_path = API_PATH["documents"]
id: int | None = None
mode: RetrieveFileMode | None = None
original: bool | None = None
content: bytes | None = None
content_type: str | None = None
disposition_filename: str | None = None
disposition_type: str | None = None
async def load(self) -> None:
"""Get `raw data` from DRF."""
self._api_path = self._api_path.format(pk=self._data.get("id"))
params = {
"original": "true" if self._data.get("original", False) else "false",
}
async with self._api.request("get", self._api_path, params=params) as res:
self._data.update(
{
"content": await res.read(),
"content_type": res.content_type,
}
)
if res.content_disposition is not None:
self._data.update(
{
"disposition_filename": res.content_disposition.filename,
"disposition_type": res.content_disposition.type,
}
)
self._set_dataclass_fields()
self._fetched = True
@dataclass(init=False)
class DocumentSuggestions(PaperlessModel):
"""Represent a Paperless `Document` suggestions."""
_api_path = API_PATH["documents_suggestions"]
id: int | None = None
correspondents: list[int] | None = None
tags: list[int] | None = None
document_types: list[int] | None = None
storage_paths: list[int] | None = None
dates: list[datetime.date] | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `DocumentSuggestions` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
class DocumentSuggestionsHelper(HelperBase):
"""Represent a factory for Paperless `DocumentSuggestions` models."""
_api_path = API_PATH["documents_suggestions"]
_resource = PaperlessResource.DOCUMENTS
_resource_cls = DocumentSuggestions
async def __call__(self, pk: int) -> DocumentSuggestions:
"""Request exactly one resource item."""
data = {
"id": pk,
}
item = self._resource_cls.create_with_data(self._api, data)
await item.load()
return item
class DocumentSubHelperBase(HelperBase):
"""Represent a factory for Paperless `DownloadedDocument` models."""
_api_path = API_PATH["documents_suggestions"]
_resource = PaperlessResource.DOCUMENTS
_resource_cls = DownloadedDocument
async def __call__(
self,
pk: int,
mode: RetrieveFileMode,
api_path: str,
*,
original: bool,
) -> DownloadedDocument:
"""Request exactly one resource item."""
data = {
"id": pk,
"mode": mode,
"original": original,
}
item = self._resource_cls.create_with_data(self._api, data)
item._api_path = api_path # noqa: SLF001
await item.load()
return item
class DocumentFileDownloadHelper(DocumentSubHelperBase):
"""Represent a factory for Paperless `DownloadedDocument` models."""
_api_path = API_PATH["documents_download"]
async def __call__( # type: ignore[override]
self,
pk: int,
*,
original: bool = False,
) -> DownloadedDocument:
"""Request exactly one resource item."""
return await super().__call__(
pk, RetrieveFileMode.DOWNLOAD, self._api_path, original=original
)
class DocumentFilePreviewHelper(DocumentSubHelperBase):
"""Represent a factory for Paperless `DownloadedDocument` models."""
_api_path = API_PATH["documents_preview"]
async def __call__( # type: ignore[override]
self,
pk: int,
*,
original: bool = False,
) -> DownloadedDocument:
"""Request exactly one resource item."""
return await super().__call__(
pk, RetrieveFileMode.PREVIEW, self._api_path, original=original
)
class DocumentFileThumbnailHelper(DocumentSubHelperBase):
"""Represent a factory for Paperless `DownloadedDocument` models."""
_api_path = API_PATH["documents_thumbnail"]
async def __call__( # type: ignore[override]
self,
pk: int,
*,
original: bool = False,
) -> DownloadedDocument:
"""Request exactly one resource item."""
return await super().__call__(
pk, RetrieveFileMode.THUMBNAIL, self._api_path, original=original
)
class DocumentMetaHelper(HelperBase, helpers.CallableMixin[DocumentMeta]):
"""Represent a factory for Paperless `DocumentMeta` models."""
_api_path = API_PATH["documents_meta"]
_resource = PaperlessResource.DOCUMENTS
_resource_cls = DocumentMeta
class DocumentNoteHelper(HelperBase):
"""Represent a factory for Paperless `DocumentNote` models."""
_api_path = API_PATH["documents_notes"]
_resource = PaperlessResource.DOCUMENTS
_resource_cls = DocumentNote
def __init__(self, api: "Paperless", attached_to: int | None = None) -> None:
"""Initialize a `DocumentHelper` instance."""
super().__init__(api)
self._attached_to = attached_to
async def __call__(
self,
pk: int | None = None,
) -> list[DocumentNote]:
"""Request and return the documents `DocumentNote` list."""
doc_pk = self._get_document_pk(pk)
res = await self._api.request_json("get", self._get_api_path(doc_pk))
# We have to transform data here slightly.
# There are two major differences in the data depending on which endpoint is requested.
# url: documents/{:pk}/ ->
# .document -> int
# .user -> int
# url: documents/{:pk}/notes/ ->
# .document -> does not exist (so we add it here)
# .user -> dict(id=int, username=str, first_name=str, last_name=str)
return [
self._resource_cls.create_with_data(
self._api,
{
**item,
"document": doc_pk,
"user": item["user"]["id"] if self._api.host_api_version >= 8 else item["user"],
},
fetched=True,
)
for item in res
]
def _get_document_pk(self, pk: int | None = None) -> int:
"""Return the attached document pk, or the parameter."""
if not any((self._attached_to, pk)):
message = f"Accessing {type(self).__name__} data without a primary key."
raise PrimaryKeyRequiredError(message)
return cast("int", self._attached_to or pk)
def _get_api_path(self, pk: int) -> str:
"""Return the formatted api path."""
return self._api_path.format(pk=pk)
def draft(self, pk: int | None = None, **kwargs: Any) -> DocumentNoteDraft:
"""Return a fresh and empty `DocumentNoteDraft` instance.
Example:
-------
```python
draft = paperless.documents.notes.draft(...)
# do something
```
"""
kwargs.update({"document": self._get_document_pk(pk)})
return DocumentNoteDraft.create_with_data(
self._api,
data=kwargs,
fetched=True,
)
class DocumentHelper(
HelperBase,
helpers.SecurableMixin,
helpers.CallableMixin[Document],
helpers.DraftableMixin[DocumentDraft],
helpers.IterableMixin[Document],
):
"""Represent a factory for Paperless `Document` models."""
_api_path = API_PATH["documents"]
_resource = PaperlessResource.DOCUMENTS
_draft_cls = DocumentDraft
_resource_cls = Document
def __init__(self, api: "Paperless") -> None:
"""Initialize a `DocumentHelper` instance."""
super().__init__(api)
self._download = DocumentFileDownloadHelper(api)
self._meta = DocumentMetaHelper(api)
self._notes = DocumentNoteHelper(api)
self._preview = DocumentFilePreviewHelper(api)
self._suggestions = DocumentSuggestionsHelper(api)
self._thumbnail = DocumentFileThumbnailHelper(api)
@property
def download(self) -> DocumentFileDownloadHelper:
"""Download the contents of an archived file.
Example:
-------
```python
# request document contents directly...
download = await paperless.documents.download(42)
# ... or by using an already fetched document
doc = await paperless.documents(42)
download = await doc.get_download()
```
"""
return self._download
@property
def metadata(self) -> DocumentMetaHelper:
"""Return the attached `DocumentMetaHelper` instance.
Example:
-------
```python
# request metadata of a document directly...
metadata = await paperless.documents.metadata(42)
# ... or by using an already fetched document
doc = await paperless.documents(42)
metadata = await doc.get_metadata()
```
"""
return self._meta
@property
def notes(self) -> DocumentNoteHelper:
"""Return the attached `DocumentNoteHelper` instance.
Example:
-------
```python
# request document notes directly...
notes = await paperless.documents.notes(42)
# ... or by using an already fetched document
doc = await paperless.documents(42)
notes = await doc.notes()
```
"""
return self._notes
@property
def preview(self) -> DocumentFilePreviewHelper:
"""Preview the contents of an archived file.
Example:
-------
```python
# request document contents directly...
download = await paperless.documents.preview(42)
# ... or by using an already fetched document
doc = await paperless.documents(42)
download = await doc.get_preview()
```
"""
return self._preview
@property
def suggestions(self) -> DocumentSuggestionsHelper:
"""Return the attached `DocumentSuggestionsHelper` instance.
Example:
-------
```python
# request document suggestions directly...
suggestions = await paperless.documents.suggestions(42)
# ... or by using an already fetched document
doc = await paperless.suggestions(42)
suggestions = await doc.get_suggestions()
```
"""
return self._suggestions
@property
def thumbnail(self) -> DocumentFileThumbnailHelper:
"""Download the contents of a thumbnail file.
Example:
-------
```python
# request document contents directly...
download = await paperless.documents.thumbnail(42)
# ... or by using an already fetched document
doc = await paperless.documents(42)
download = await doc.get_thumbnail()
```
"""
return self._thumbnail
async def get_next_asn(self) -> int:
"""Request the next archive serial number from DRF."""
async with self._api.request("get", API_PATH["documents_next_asn"]) as res:
try:
res.raise_for_status()
return int(await res.text())
except Exception as exc:
raise AsnRequestError from exc
async def more_like(self, pk: int) -> AsyncGenerator[Document]:
"""Lookup documents similar to the given document pk.
Shortcut function. Same behaviour is possible using `reduce()`.
Documentation: https://docs.paperless-ngx.com/api/#searching-for-documents
"""
async with self.reduce(more_like_id=pk):
async for item in self:
yield item
async def search(self, query: str) -> AsyncGenerator[Document]:
"""Lookup documents by a search query.
Shortcut function. Same behaviour is possible using `reduce()`.
Documentation: https://docs.paperless-ngx.com/usage/#basic-usage_searching
"""
async with self.reduce(query=query):
async for item in self:
yield item
paperless-api-5.1.0/pypaperless/models/generators/ 0000775 0000000 0000000 00000000000 15053074171 0022270 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pypaperless/models/generators/__init__.py 0000664 0000000 0000000 00000000135 15053074171 0024400 0 ustar 00root root 0000000 0000000 """PyPaperless generators."""
from .page import PageGenerator
__all__ = ("PageGenerator",)
paperless-api-5.1.0/pypaperless/models/generators/page.py 0000664 0000000 0000000 00000004100 15053074171 0023551 0 ustar 00root root 0000000 0000000 """Provide the PageGenerator class."""
from collections.abc import AsyncIterator
from copy import deepcopy
from typing import TYPE_CHECKING, Any, Self
from pypaperless.models.base import PaperlessBase
from pypaperless.models.pages import Page
if TYPE_CHECKING:
from pypaperless import Paperless
class PageGenerator(PaperlessBase, AsyncIterator):
"""Iterator for DRF paginated endpoints.
`api`: An instance of :class:`Paperless`.
`url`: A url returning DRF page contents.
`resource`: A target resource model type for mapping results with.
`params`: Optional dict of query string parameters.
"""
_page: Page | None
def __aiter__(self) -> Self:
"""Return self as iterator."""
return self
async def __anext__(self) -> Page:
"""Return next item from the current batch."""
if self._page is not None and self._page.is_last_page:
raise StopAsyncIteration
res = await self._api.request_json("get", self._url, params=self.params)
data = {
**res,
"_api_path": self._url,
"current_page": self.params["page"],
"page_size": self.params["page_size"],
}
self._page = Page.create_with_data(self._api, data, fetched=True)
# dirty attach the resource to the data class
self._page._resource_cls = self._resource_cls # noqa: SLF001
# rise page by one to request next page on next iteration
self.params["page"] += 1
# we do not reach this point without a self._page object, so: ignore type error
return self._page
def __init__(
self,
api: "Paperless",
url: str,
resource_cls: type,
params: dict[str, Any] | None = None,
) -> None:
"""Initialize `PageGenerator` class instance."""
super().__init__(api)
self._page = None
self._resource_cls = resource_cls
self._url = url
self.params = deepcopy(params) if params else {}
self.params.setdefault("page", 1)
self.params.setdefault("page_size", 150)
paperless-api-5.1.0/pypaperless/models/mails.py 0000664 0000000 0000000 00000006132 15053074171 0021600 0 ustar 00root root 0000000 0000000 """Provide `MailRule` related models and helpers."""
import datetime
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .mixins import helpers, models
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class MailAccount(PaperlessModel, models.SecurableMixin):
"""Represent a Paperless `MailAccount`."""
_api_path = API_PATH["mail_accounts_single"]
id: int | None = None
name: str | None = None
imap_server: str | None = None
imap_port: int | None = None
imap_security: int | None = None
username: str | None = None
# exclude that from the dataclass
# password: str | None = None # noqa: ERA001
character_set: str | None = None
is_token: bool | None = None
account_type: int | None = None
expiration: datetime.datetime | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `MailAccount` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class MailRule(PaperlessModel, models.SecurableMixin):
"""Represent a Paperless `MailRule`."""
_api_path = API_PATH["mail_rules_single"]
id: int | None = None
name: str | None = None
account: int | None = None
enabled: bool | None = None
folder: str | None = None
filter_from: str | None = None
filter_to: str | None = None
filter_subject: str | None = None
filter_body: str | None = None
filter_attachment_filename_include: str | None = None
filter_attachment_filename_exclude: str | None = None
maximum_age: int | None = None
action: int | None = None
action_parameter: str | None = None
assign_title_from: int | None = None
assign_tags: list[int] | None = None
assign_correspondent_from: int | None = None
assign_correspondent: int | None = None
assign_document_type: int | None = None
assign_owner_from_rule: bool | None = None
order: int | None = None
attachment_type: int | None = None
consumption_scope: int | None = None
pdf_layout: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `MailRule` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
class MailAccountHelper(
HelperBase,
helpers.CallableMixin[MailAccount],
helpers.IterableMixin[MailAccount],
helpers.SecurableMixin,
):
"""Represent a factory for Paperless `MailAccount` models."""
_api_path = API_PATH["mail_accounts"]
_resource = PaperlessResource.MAIL_ACCOUNTS
_resource_cls = MailAccount
class MailRuleHelper(
HelperBase,
helpers.CallableMixin[MailRule],
helpers.IterableMixin[MailRule],
helpers.SecurableMixin,
):
"""Represent a factory for Paperless `MailRule` models."""
_api_path = API_PATH["mail_rules"]
_resource = PaperlessResource.MAIL_RULES
_resource_cls = MailRule
paperless-api-5.1.0/pypaperless/models/mixins/ 0000775 0000000 0000000 00000000000 15053074171 0021426 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pypaperless/models/mixins/__init__.py 0000664 0000000 0000000 00000000045 15053074171 0023536 0 ustar 00root root 0000000 0000000 """Mixins for PyPaperless models."""
paperless-api-5.1.0/pypaperless/models/mixins/helpers/ 0000775 0000000 0000000 00000000000 15053074171 0023070 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pypaperless/models/mixins/helpers/__init__.py 0000664 0000000 0000000 00000000440 15053074171 0025177 0 ustar 00root root 0000000 0000000 """Mixins for PyPaperless helpers."""
from .callable import CallableMixin
from .draftable import DraftableMixin
from .iterable import IterableMixin
from .securable import SecurableMixin
__all__ = (
"CallableMixin",
"DraftableMixin",
"IterableMixin",
"SecurableMixin",
)
paperless-api-5.1.0/pypaperless/models/mixins/helpers/callable.py 0000664 0000000 0000000 00000001761 15053074171 0025206 0 ustar 00root root 0000000 0000000 """CallableMixin for PyPaperless helpers."""
from pypaperless.models.base import HelperProtocol, ResourceT
class CallableMixin(HelperProtocol[ResourceT]):
"""Provide methods for calling a specific resource item."""
async def __call__(
self,
pk: int,
*,
lazy: bool = False,
) -> ResourceT:
"""Request exactly one resource item.
Example:
-------
```python
# request a document
document = await paperless.documents(42)
# initialize a model and request it later
document = await paperless.documents(42, lazy=True)
```
"""
data = {
"id": pk,
}
item = self._resource_cls.create_with_data(self._api, data)
# set requesting full permissions
if getattr(self, "_request_full_perms", False):
item._params.update({"full_perms": "true"}) # noqa: SLF001
if not lazy:
await item.load()
return item
paperless-api-5.1.0/pypaperless/models/mixins/helpers/draftable.py 0000664 0000000 0000000 00000001624 15053074171 0025371 0 ustar 00root root 0000000 0000000 """DraftableMixin for PyPaperless helpers."""
from typing import Any
from pypaperless.exceptions import DraftNotSupportedError
from pypaperless.models.base import HelperProtocol, ResourceT
class DraftableMixin(HelperProtocol[ResourceT]):
"""Provide the `draft` method for PyPaperless helpers."""
_draft_cls: type[ResourceT]
def draft(self, **kwargs: Any) -> ResourceT:
"""Return a fresh and empty `PaperlessModel` instance.
Example:
-------
```python
draft = paperless.documents.draft(document=bytes(...), title="New Document")
# do something
```
"""
if not hasattr(self, "_draft_cls"):
message = "Helper class has no _draft_cls attribute."
raise DraftNotSupportedError(message)
kwargs.update({"id": -1})
return self._draft_cls.create_with_data(self._api, data=kwargs, fetched=True)
paperless-api-5.1.0/pypaperless/models/mixins/helpers/iterable.py 0000664 0000000 0000000 00000007336 15053074171 0025242 0 ustar 00root root 0000000 0000000 """IterableMixin for PyPaperless helpers."""
from collections.abc import AsyncGenerator, AsyncIterator
from contextlib import asynccontextmanager
from typing import TYPE_CHECKING, Any, Self
from pypaperless.models.base import HelperProtocol, ResourceT
from pypaperless.models.generators import PageGenerator
if TYPE_CHECKING:
from pypaperless.models import Page
class IterableMixin(HelperProtocol[ResourceT]):
"""Provide methods for iterating over resource items."""
_aiter_filters: dict[str, str | int] | None
async def __aiter__(self) -> AsyncIterator[ResourceT]:
"""Iterate over resource items.
Example:
-------
```python
async for item in paperless.documents:
# do something
```
"""
async for page in self.pages():
for item in page:
yield item
@asynccontextmanager
async def reduce(
self: Self,
**kwargs: str | int,
) -> AsyncGenerator[Self]:
"""Provide context for iterating over resource items with query parameters.
`kwargs`: Insert any Paperless api supported filter keywords here.
You can provide `page` and `page_size` parameters, as well.
Example:
-------
```python
filters = {
"page_size": 1337,
"title__icontains": "2023",
}
async with paperless.documents.reduce(**filters):
# iterate over resource items ...
async for item in paperless.documents:
...
# ... or iterate pages as-is
async for page in paperless.documents.pages():
...
```
"""
self._aiter_filters = kwargs
yield self
self._aiter_filters = None
async def all(self) -> list[int]:
"""Return a list of all resource item primary keys.
When used within a `reduce` context, returns a list of filtered primary keys.
"""
page = await anext(self.pages(page=1))
return page.all
async def as_dict(self) -> dict[int, ResourceT]:
"""Shortcut for returning a primary key/object dict of all resource items.
When used within a `reduce` context, data is filtered.
"""
return {item.id: item async for item in self} # type: ignore[attr-defined]
async def as_list(self) -> list[ResourceT]:
"""Shortcut for returning a list of all resource items.
When used within a `reduce` context, data is filtered.
"""
return [item async for item in self]
def pages(
self,
page: int = 1,
page_size: int = 150,
) -> "AsyncIterator[Page[ResourceT]]":
"""Iterate over resource pages.
`page`: A page number to start with.
`page_size`: The page size for each requested batch.
Example:
-------
```python
async for item in paperless.documents.pages():
# do something
```
"""
params: dict[str, Any] = getattr(self, "_aiter_filters", None) or {}
for param, value in params.items():
if param.endswith("__in"):
try:
value.extend([]) # throw AttributeError if not a list
params[param] = ",".join(map(str, value))
except AttributeError:
# value is not a list, don't modify
continue
params.setdefault("page", page)
params.setdefault("page_size", page_size)
# set requesting full permissions
if getattr(self, "_request_full_perms", False):
params.update({"full_perms": "true"})
return PageGenerator(self._api, self._api_path, self._resource_cls, params=params)
paperless-api-5.1.0/pypaperless/models/mixins/helpers/securable.py 0000664 0000000 0000000 00000001375 15053074171 0025415 0 ustar 00root root 0000000 0000000 """SecurableMixin for PyPaperless helpers."""
class SecurableMixin:
"""Provide the `request_full_permissions` property for PyPaperless helpers."""
_request_full_perms: bool = False
@property
def request_permissions(self) -> bool:
"""Return whether the helper requests items with the `permissions` table, or not.
Documentation: https://docs.paperless-ngx.com/api/#permissions
"""
return self._request_full_perms
@request_permissions.setter
def request_permissions(self, value: bool) -> None:
"""Set whether the helper requests items with the `permissions` table, or not.
Documentation: https://docs.paperless-ngx.com/api/#permissions
"""
self._request_full_perms = value
paperless-api-5.1.0/pypaperless/models/mixins/models/ 0000775 0000000 0000000 00000000000 15053074171 0022711 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pypaperless/models/mixins/models/__init__.py 0000664 0000000 0000000 00000000635 15053074171 0025026 0 ustar 00root root 0000000 0000000 """Mixins for PyPaperless models."""
from .creatable import CreatableMixin
from .data_fields import MatchingFieldsMixin
from .deletable import DeletableMixin
from .securable import SecurableDraftMixin, SecurableMixin
from .updatable import UpdatableMixin
__all__ = (
"CreatableMixin",
"DeletableMixin",
"MatchingFieldsMixin",
"SecurableDraftMixin",
"SecurableMixin",
"UpdatableMixin",
)
paperless-api-5.1.0/pypaperless/models/mixins/models/creatable.py 0000664 0000000 0000000 00000004175 15053074171 0025214 0 ustar 00root root 0000000 0000000 """CreatableMixin for PyPaperless models."""
from typing import Any, cast
from pypaperless.exceptions import DraftFieldRequiredError
from pypaperless.models.base import PaperlessModelProtocol
from pypaperless.models.utils import object_to_dict_value
class CreatableMixin(PaperlessModelProtocol):
"""Provide the `save` method for PyPaperless models."""
_create_required_fields: set[str]
async def save(self) -> int | str | tuple[int, int]:
"""Create a new `resource item` in Paperless.
Return the created item `id`, or a `task_id` in case of documents.
Example:
-------
```python
draft = paperless.documents.draft(document=bytes(...))
draft.title = "Add a title"
# request Paperless to store the new item
draft.save()
```
"""
self.validate()
kwdict = self._serialize()
res = await self._api.request_json("post", self._api_path, **kwdict)
if type(self).__name__ == "DocumentNoteDraft":
return (
cast("int", max(item.get("id") for item in res)),
cast("int", kwdict["json"]["document"]),
)
if isinstance(res, dict):
return int(res["id"])
return str(res)
def _serialize(self) -> dict[str, Any]:
"""Serialize."""
data = {
"json": {
field.name: object_to_dict_value(getattr(self, field.name))
for field in self._get_dataclass_fields()
},
}
# check for empty permissions as they will raise if None
if "set_permissions" in data["json"] and data["json"]["set_permissions"] is None:
del data["json"]["set_permissions"]
return data
def validate(self) -> None:
"""Check required fields before persisting the item to Paperless."""
missing = [field for field in self._create_required_fields if getattr(self, field) is None]
if len(missing) == 0:
return
message = f"Missing fields for saving a `{type(self).__name__}`: {', '.join(missing)}."
raise DraftFieldRequiredError(message)
paperless-api-5.1.0/pypaperless/models/mixins/models/data_fields.py 0000664 0000000 0000000 00000000576 15053074171 0025532 0 ustar 00root root 0000000 0000000 """PermissionFieldsMixin for PyPaperless models."""
from dataclasses import dataclass
from pypaperless.models.common import MatchingAlgorithmType
@dataclass
class MatchingFieldsMixin:
"""Provide shared matching fields for PyPaperless models."""
match: str | None = None
matching_algorithm: MatchingAlgorithmType | None = None
is_insensitive: bool | None = None
paperless-api-5.1.0/pypaperless/models/mixins/models/deletable.py 0000664 0000000 0000000 00000001363 15053074171 0025207 0 ustar 00root root 0000000 0000000 """DeletableMixin for PyPaperless models."""
from pypaperless.models.base import PaperlessModelProtocol
class DeletableMixin(PaperlessModelProtocol):
"""Provide the `delete` method for PyPaperless models."""
async def delete(self) -> bool:
"""Delete a `resource item` from DRF. There is no point of return.
Return `True` when deletion was successful, `False` otherwise.
Example:
-------
```python
# request a document
document = await paperless.documents(42)
if await document.delete():
print("Successfully deleted the document!")
```
"""
async with self._api.request("delete", self._api_path) as res:
return res.status == 204
paperless-api-5.1.0/pypaperless/models/mixins/models/securable.py 0000664 0000000 0000000 00000001346 15053074171 0025234 0 ustar 00root root 0000000 0000000 """SecurableMixin for PyPaperless models."""
from dataclasses import dataclass
from pypaperless.models.common import PermissionTableType
@dataclass(kw_only=True)
class SecurableMixin:
"""Provide permission fields for PyPaperless models."""
owner: int | None = None
user_can_change: bool | None = None
permissions: PermissionTableType | None = None
@property
def has_permissions(self) -> bool:
"""Return if the model data includes the permission field."""
return self.permissions is not None
@dataclass(kw_only=True)
class SecurableDraftMixin:
"""Provide permission fields for PyPaperless draft models."""
owner: int | None = None
set_permissions: PermissionTableType | None = None
paperless-api-5.1.0/pypaperless/models/mixins/models/updatable.py 0000664 0000000 0000000 00000005121 15053074171 0025223 0 ustar 00root root 0000000 0000000 """UpdatableMixin for PyPaperless models."""
from copy import deepcopy
from typing import Any
from pypaperless.models.base import PaperlessModelProtocol
from pypaperless.models.utils import object_to_dict_value
from .securable import SecurableMixin
class UpdatableMixin(PaperlessModelProtocol):
"""Provide the `update` method for PyPaperless models."""
_data: dict[str, Any]
async def update(self, *, only_changed: bool = True) -> bool:
"""Send actually changed `model data` to DRF.
Return `True` when any attribute was updated, `False` otherwise.
Example:
-------
```python
# request a document
document = await paperless.documents(42)
document.title = "New Title"
if await document.update():
print("Successfully updated a field!")
```
"""
updated = False
if only_changed:
updated = await self._patch_fields()
else:
updated = await self._put_fields()
self._set_dataclass_fields()
return updated
def _check_permissions_field(self, data: dict) -> None:
"""Check."""
if SecurableMixin not in type(self).__bases__:
return
if not self.has_permissions: # type: ignore[attr-defined]
return
if "permissions" in data:
data["set_permissions"] = deepcopy(data["permissions"])
del data["permissions"]
async def _patch_fields(self) -> bool:
"""Use the http `PATCH` method for updating only changed fields."""
changed = {}
for field in self._get_dataclass_fields():
new_value = object_to_dict_value(getattr(self, field.name))
if field.name in self._data and new_value != self._data[field.name]:
changed[field.name] = new_value
if len(changed) == 0:
return False
self._check_permissions_field(changed)
self._data = await self._api.request_json(
"patch",
self._api_path,
json=changed,
params=self._params,
)
return True
async def _put_fields(self) -> bool:
"""Use the http `PUT` method to replace all fields."""
data = {
field.name: object_to_dict_value(getattr(self, field.name))
for field in self._get_dataclass_fields()
}
self._check_permissions_field(data)
self._data = await self._api.request_json(
"put",
self._api_path,
json=data,
params=self._params,
)
return True
paperless-api-5.1.0/pypaperless/models/pages.py 0000664 0000000 0000000 00000005105 15053074171 0021571 0 ustar 00root root 0000000 0000000 """Provide the `Paginated` class."""
import math
from collections.abc import Iterator
from dataclasses import dataclass, field
from typing import Any, Generic
from pypaperless.const import API_PATH
from .base import PaperlessModel, ResourceT
@dataclass(init=False)
class Page(PaperlessModel, Generic[ResourceT]): # noqa: UP046
"""Represent a Paperless DRF `Paginated`."""
_api_path = API_PATH["index"]
_resource_cls: type[ResourceT]
# our fields
current_page: int
page_size: int
# DRF fields
count: int
next: str | None = None
previous: str | None = None
all: list[int] = field(default_factory=list)
results: list[dict[str, Any]] = field(default_factory=list)
def __iter__(self) -> Iterator[ResourceT]:
"""Return iter of `.items`."""
return iter(self.items)
@property
def current_count(self) -> int:
"""Return the item count of the current page."""
return len(self.results)
@property
def has_next_page(self) -> bool:
"""Return whether there is a next page or not."""
return self.next_page is not None
@property
def has_previous_page(self) -> bool:
"""Return whether there is a previous page or not."""
return self.previous_page is not None
@property
def items(self) -> list[ResourceT]:
"""Return the results list field with mapped PyPaperless `models`.
Example:
-------
```python
async for page in paperless.documents.pages():
assert isinstance(page.results.pop(), Document) # fails, it is a dict
assert isinstance(page.items.pop(), Document) # ok
```
"""
def mapper(data: dict[str, Any]) -> ResourceT:
return self._resource_cls.create_with_data(self._api, data, fetched=True)
return list(map(mapper, self._data["results"]))
@property
def is_last_page(self) -> bool:
"""Return whether we are on the last page or not."""
return not self.has_next_page
@property
def last_page(self) -> int:
"""Return the last page number."""
return math.ceil(self.count / self.page_size)
@property
def next_page(self) -> int | None:
"""Return the next page number if a next page exists."""
if self.next is None:
return None
return self.current_page + 1
@property
def previous_page(self) -> int | None:
"""Return the previous page number if a previous page exists."""
if self.previous is None:
return None
return self.current_page - 1
paperless-api-5.1.0/pypaperless/models/permissions.py 0000664 0000000 0000000 00000004263 15053074171 0023051 0 ustar 00root root 0000000 0000000 """Provide `User` and 'Group' related models and helpers."""
import datetime
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .mixins import helpers
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class Group(PaperlessModel):
"""Represent a Paperless `Group`."""
_api_path = API_PATH["groups_single"]
id: int
name: str | None = None
permissions: list[str] | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Group` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class User(PaperlessModel):
"""Represent a Paperless `User`."""
_api_path = API_PATH["users_single"]
id: int
username: str | None = None
# exclude that from the dataclass
# password: str | None = None # noqa: ERA001
email: str | None = None
first_name: str | None = None
last_name: str | None = None
date_joined: datetime.datetime | None = None
is_staff: bool | None = None
is_active: bool | None = None
is_superuser: bool | None = None
groups: list[int] | None = None
user_permissions: list[str] | None = None
inherited_permissions: list[str] | None = None
is_mfa_enabled: bool | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `User` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
class GroupHelper(
HelperBase,
helpers.CallableMixin[Group],
helpers.IterableMixin[Group],
):
"""Represent a factory for Paperless `Group` models."""
_api_path = API_PATH["groups"]
_resource = PaperlessResource.GROUPS
_resource_cls = Group
class UserHelper(
HelperBase,
helpers.CallableMixin[User],
helpers.IterableMixin[User],
):
"""Represent a factory for Paperless `User` models."""
_api_path = API_PATH["users"]
_resource = PaperlessResource.USERS
_resource_cls = User
paperless-api-5.1.0/pypaperless/models/remote_version.py 0000664 0000000 0000000 00000001622 15053074171 0023532 0 ustar 00root root 0000000 0000000 """Provide `Remote Version` related models and helpers."""
from dataclasses import dataclass
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
@dataclass(init=False)
class RemoteVersion(PaperlessModel):
"""Represent Paperless `Remote Version`."""
_api_path = API_PATH["remote_version"]
version: str | None = None
update_available: bool | None = None
class RemoteVersionHelper(HelperBase):
"""Represent a factory for Paperless `Remote Version` models."""
_api_path = API_PATH["remote_version"]
_resource = PaperlessResource.REMOTE_VERSION
_resource_cls = RemoteVersion
async def __call__(self) -> RemoteVersion:
"""Request the `Remote Version` model data."""
res = await self._api.request_json("get", self._api_path)
return self._resource_cls.create_with_data(self._api, res, fetched=True)
paperless-api-5.1.0/pypaperless/models/saved_views.py 0000664 0000000 0000000 00000002711 15053074171 0023011 0 ustar 00root root 0000000 0000000 """Provide `SavedView` related models and helpers."""
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .common import SavedViewFilterRuleType
from .mixins import helpers, models
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class SavedView(PaperlessModel, models.SecurableMixin):
"""Represent a Paperless `SavedView`."""
_api_path = API_PATH["saved_views_single"]
id: int | None = None
name: str | None = None
show_on_dashboard: bool | None = None
show_in_sidebar: bool | None = None
sort_field: str | None = None
sort_reverse: bool | None = None
filter_rules: list[SavedViewFilterRuleType] | None = None
page_size: int | None = None
display_mode: str | None = None
display_fields: list[str] | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `SavedView` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
class SavedViewHelper(
HelperBase,
helpers.CallableMixin[SavedView],
helpers.IterableMixin[SavedView],
helpers.SecurableMixin,
):
"""Represent a factory for Paperless `SavedView` models."""
_api_path = API_PATH["saved_views"]
_resource = PaperlessResource.SAVED_VIEWS
_resource_cls = SavedView
paperless-api-5.1.0/pypaperless/models/share_links.py 0000664 0000000 0000000 00000003450 15053074171 0022775 0 ustar 00root root 0000000 0000000 """Provide `ShareLink` related models and helpers."""
import datetime
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .common import ShareLinkFileVersionType
from .mixins import helpers, models
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class ShareLink(
PaperlessModel,
models.DeletableMixin,
models.UpdatableMixin,
):
"""Represent a Paperless `ShareLink`."""
_api_path = API_PATH["share_links_single"]
id: int
created: datetime.datetime | None = None
expiration: datetime.datetime | None = None
slug: str | None = None
document: int | None = None
file_version: ShareLinkFileVersionType | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `ShareLink` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class ShareLinkDraft(PaperlessModel, models.CreatableMixin):
"""Represent a new Paperless `ShareLink`, which is not stored in Paperless."""
_api_path = API_PATH["share_links"]
_create_required_fields = {"document", "file_version"}
expiration: datetime.datetime | None = None
document: int | None = None
file_version: ShareLinkFileVersionType | None = None
class ShareLinkHelper(
HelperBase,
helpers.CallableMixin[ShareLink],
helpers.DraftableMixin[ShareLinkDraft],
helpers.IterableMixin[ShareLink],
):
"""Represent a factory for Paperless `ShareLink` models."""
_api_path = API_PATH["share_links"]
_resource = PaperlessResource.SHARE_LINKS
_draft_cls = ShareLinkDraft
_resource_cls = ShareLink
paperless-api-5.1.0/pypaperless/models/statistics.py 0000664 0000000 0000000 00000002442 15053074171 0022665 0 ustar 00root root 0000000 0000000 """Provide `Statistics` related models and helpers."""
from dataclasses import dataclass
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .common import StatisticDocumentFileTypeCount
@dataclass(init=False)
class Statistic(PaperlessModel):
"""Represent Paperless `Statistic`."""
_api_path = API_PATH["statistics"]
documents_total: int | None = None
documents_inbox: int | None = None
inbox_tag: int | None = None
inbox_tags: list[int] | None = None
document_file_type_counts: list[StatisticDocumentFileTypeCount] | None = None
character_count: int | None = None
tag_count: int | None = None
correspondent_count: int | None = None
document_type_count: int | None = None
storage_path_count: int | None = None
current_asn: int | None = None
class StatisticHelper(HelperBase):
"""Represent a factory for Paperless `Statistic` models."""
_api_path = API_PATH["statistics"]
_resource = PaperlessResource.STATISTICS
_resource_cls = Statistic
async def __call__(self) -> Statistic:
"""Request the `Statistic` model data."""
res = await self._api.request_json("get", self._api_path)
return self._resource_cls.create_with_data(self._api, res, fetched=True)
paperless-api-5.1.0/pypaperless/models/status.py 0000664 0000000 0000000 00000003347 15053074171 0022023 0 ustar 00root root 0000000 0000000 """Provide `Status` related models and helpers."""
from dataclasses import dataclass
from typing import cast
from pypaperless.const import API_PATH, PaperlessResource
from pypaperless.models.common import (
StatusDatabaseType,
StatusStorageType,
StatusTasksType,
StatusType,
)
from .base import HelperBase, PaperlessModel
@dataclass(init=False)
class Status(PaperlessModel):
"""Represent a Paperless `Status`."""
_api_path = API_PATH["status"]
pngx_version: str | None = None
server_os: str | None = None
install_type: str | None = None
storage: StatusStorageType | None = None
database: StatusDatabaseType | None = None
tasks: StatusTasksType | None = None
@property
def has_errors(self) -> bool:
"""Return whether any status flag is `ERROR`."""
statuses: list[StatusType] = [
self.database.status if self.database and self.database.status else StatusType.OK,
*[
cast("StatusType", getattr(self.tasks, status, StatusType.OK))
for status in (
"redis_status",
"celery_status",
"classifier_status",
)
if self.tasks
],
]
return any(st == StatusType.ERROR for st in statuses)
class StatusHelper(HelperBase):
"""Represent a factory for the Paperless `Status` model."""
_api_path = API_PATH["status"]
_resource = PaperlessResource.STATUS
_resource_cls = Status
async def __call__(self) -> Status:
"""Request the `Status` model data."""
res = await self._api.request_json("get", self._api_path)
return self._resource_cls.create_with_data(self._api, res, fetched=True)
paperless-api-5.1.0/pypaperless/models/tasks.py 0000664 0000000 0000000 00000005270 15053074171 0021622 0 ustar 00root root 0000000 0000000 """Provide `Task` related models and helpers."""
from collections.abc import AsyncIterator
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from pypaperless.exceptions import TaskNotFoundError
from .base import HelperBase, PaperlessModel
from .common import TaskStatusType
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class Task(PaperlessModel):
"""Represent a Paperless `Task`."""
_api_path = API_PATH["tasks_single"]
id: int | None = None
task_id: str | None = None
task_file_name: str | None = None
date_created: str | None = None
date_done: str | None = None
type: str | None = None
status: TaskStatusType | None = None
result: str | None = None
acknowledged: bool | None = None
related_document: int | None = None
owner: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Task` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
class TaskHelper(HelperBase):
"""Represent a factory for Paperless `Task` models."""
_api_path = API_PATH["tasks"]
_resource = PaperlessResource.TASKS
_resource_cls = Task
async def __aiter__(self) -> AsyncIterator[Task]:
"""Iterate over task items.
Example:
-------
```python
async for task in paperless.tasks:
# do something
```
"""
res = await self._api.request_json("get", self._api_path)
for data in res:
yield self._resource_cls.create_with_data(self._api, data, fetched=True)
async def __call__(self, task_id: int | str) -> Task:
"""Request exactly one task by id.
If task_id is `str`: interpret it as a task uuid.
If task_id is `int`: interpret it as a primary key.
Example:
-------
```python
task = await paperless.tasks("uuid-string")
task = await paperless.tasks(1337)
```
"""
if isinstance(task_id, str):
params = {
"task_id": task_id,
}
res = await self._api.request_json("get", self._api_path, params=params)
try:
item = self._resource_cls.create_with_data(self._api, res.pop(), fetched=True)
except IndexError as exc:
raise TaskNotFoundError(task_id) from exc
else:
data = {
"id": task_id,
}
item = self._resource_cls.create_with_data(self._api, data)
await item.load()
return item
paperless-api-5.1.0/pypaperless/models/utils/ 0000775 0000000 0000000 00000000000 15053074171 0021257 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pypaperless/models/utils/__init__.py 0000664 0000000 0000000 00000017453 15053074171 0023402 0 ustar 00root root 0000000 0000000 """Utils for pypaperless models.
Since there are common use-cases in transforming dicts to dataclass et vice-versa,
we borrowed some snippets from aiohue instead of re-inventing the wheel.
pypaperless is meant to be the api library for a Home Assistant integration,
so it should be okay I think.
https://github.com/home-assistant-libs/aiohue/
Thanks for the excellent work, guys!
"""
# mypy: ignore-errors
# pylint: disable=all
import logging
from dataclasses import MISSING, asdict, fields, is_dataclass
from datetime import date, datetime
from enum import Enum
from types import NoneType, UnionType
from typing import TYPE_CHECKING, Any, Union, get_args, get_origin, get_type_hints
import pypaperless.models.base as paperless_base
if TYPE_CHECKING:
from pypaperless import Paperless
def _str_to_datetime(datetimestr: str) -> datetime:
"""Parse datetime from string."""
return datetime.fromisoformat(datetimestr.replace("Z", "+00:00")) # noqa: FURB162
def _str_to_date(datestr: str) -> date:
"""Parse date from string."""
return datetime.fromisoformat(datestr).date()
def _dateobj_to_str(value: date | datetime) -> str:
"""Parse string from date objects."""
return value.isoformat().replace("+00:00", "Z")
def _is_typeddict(cls: type) -> bool:
"""Check whether a type is a `TypedDict` or not."""
return (
isinstance(cls, type)
and issubclass(cls, dict)
and hasattr(cls, "__annotations__")
and getattr(cls, "__total__", None) is not None
)
def object_to_dict_value(value: Any) -> Any:
"""Convert object values to their correspondending json values."""
if isinstance(value, dict):
return {k: object_to_dict_value(v) for k, v in value.items()}
if isinstance(value, list):
return [object_to_dict_value(item) for item in value]
if isinstance(value, Enum):
return value.value
if isinstance(value, (date, datetime)):
return _dateobj_to_str(value)
if isinstance(value, paperless_base.PaperlessModelData):
return object_to_dict_value(value.serialize())
if is_dataclass(value):
return object_to_dict_value(asdict(value))
return value
def dict_value_to_object( # noqa: C901, PLR0915
name: str,
value: Any,
value_type: Any,
default: Any = MISSING,
_api: "Paperless | None" = None,
) -> Any:
"""Try to parse a value from raw (json) data and type annotations.
Since there are common use-cases in transforming dicts to dataclass et vice-versa,
we borrowed some snippets from aiohue instead of re-inventing the wheel.
pypaperless is meant to be the api library for a Home Assistant integration,
so it should be okay I think.
https://github.com/home-assistant-libs/aiohue/
"""
# pypaperless addition
try:
is_paperless_model = _api is not None and issubclass(
value_type,
paperless_base.PaperlessModel,
)
except TypeError:
# happens if value_type is not a class
is_paperless_model = False
try:
is_paperless_data = _api is not None and issubclass(
value_type,
paperless_base.PaperlessModelData,
)
except TypeError:
# happens if value_type is not a class
is_paperless_data = False
# ruff: noqa: PLR0911, PLR0912
if isinstance(value_type, str):
# this shouldn't happen, but just in case
value_type = get_type_hints(value_type, globals(), locals())
if is_paperless_data:
# create class instance if its custom data
return value_type.unserialize(api=_api, data=value)
if isinstance(value, dict):
# always prefer classes that have a from_dict
if hasattr(value_type, "from_dict"):
return value_type.from_dict(value)
# pypaperless addition for typeddicts
if _is_typeddict(value_type):
return value
if value is None and not isinstance(default, type(MISSING)):
return default
if value is None and value_type is NoneType:
return None
if is_dataclass(value_type) and isinstance(value, dict):
if is_paperless_model:
return value_type.create_with_data(api=_api, data=value, fetched=True)
return value_type(
**{
field.name: dict_value_to_object(
f"{value_type.__name__}.{field.name}",
value.get(field.name),
field.type,
field.default,
_api,
)
for field in fields(value_type)
}
)
# get origin value type and inspect one-by-one
origin: Any = get_origin(value_type)
if origin in (list, tuple, set) and isinstance(value, list | tuple | set):
return origin(
dict_value_to_object(name, subvalue, get_args(value_type)[0], _api=_api)
for subvalue in value
if subvalue is not None
)
# handle dictionary where we should inspect all values
if origin is dict:
subkey_type = get_args(value_type)[0]
subvalue_type = get_args(value_type)[1]
return {
dict_value_to_object(subkey, subkey, subkey_type, _api=_api): dict_value_to_object(
f"{subkey}.value", subvalue, subvalue_type, _api=_api
)
for subkey, subvalue in value.items()
}
# handle Union type
if origin is Union or origin is UnionType:
# try all possible types
sub_value_types = get_args(value_type)
for sub_arg_type in sub_value_types:
if value is NoneType and sub_arg_type is NoneType:
return value
if value == {} and sub_arg_type is NoneType:
# handle case where optional value is received as empty dict from api
return None
# try them all until one succeeds
try:
return dict_value_to_object(name, value, sub_arg_type, _api=_api)
except (KeyError, TypeError, ValueError):
pass
# if we get to this point, all possibilities failed
# find out if we should raise or log this
err = (
f"Value {value} of type {type(value)} is invalid for {name}, "
f"expected value of type {value_type}"
)
if NoneType not in sub_value_types:
# raise exception, we have no idea how to handle this value
raise TypeError(err)
# failed to parse the (sub) value but None allowed, log only
logging.getLogger(__name__).warning(err)
return None
if origin is type:
return get_type_hints(value, globals(), locals())
# handle Any as value type (which is basically unprocessable)
if value_type is Any:
return value
# raise if value is None and the value is required according to annotations
if value is None and value_type is not NoneType:
message = f"`{name}` of type `{value_type}` is required."
raise KeyError(message)
try:
if issubclass(value_type, Enum):
return value_type(value)
if issubclass(value_type, datetime):
return _str_to_datetime(value)
if issubclass(value_type, date):
return _str_to_date(value)
except TypeError:
# happens if value_type is not a class
pass
# common type conversions (e.g. int as string)
if value_type is float and isinstance(value, int):
return float(value)
if value_type is int and isinstance(value, str) and value.isnumeric():
return int(value)
# If we reach this point, we could not match the value with the type and we raise
if not isinstance(value, value_type):
message = f"Value {value} of type {type(value)} is invalid for {name}, \
expected value of type {value_type}"
raise TypeError(message)
return value
paperless-api-5.1.0/pypaperless/models/workflows.py 0000664 0000000 0000000 00000013016 15053074171 0022527 0 ustar 00root root 0000000 0000000 """Provide `Workflow` related models and helpers."""
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from pypaperless.const import API_PATH, PaperlessResource
from .base import HelperBase, PaperlessModel
from .common import WorkflowActionType, WorkflowTriggerSourceType, WorkflowTriggerType
from .mixins import helpers, models
if TYPE_CHECKING:
from pypaperless import Paperless
@dataclass(init=False)
class WorkflowAction(PaperlessModel):
"""Represent a Paperless `WorkflowAction`."""
_api_path = API_PATH["workflow_actions_single"]
id: int | None = None
type: WorkflowActionType | None = None
assign_title: str | None = None
assign_tags: list[int] | None = None
assign_correspondent: int | None = None
assign_document_type: int | None = None
assign_storage_path: int | None = None
assign_view_users: list[int] | None = None
assign_view_groups: list[int] | None = None
assign_change_users: list[int] | None = None
assign_change_groups: list[int] | None = None
assign_custom_fields: list[int] | None = None
assign_custom_fields_values: dict[str, Any] | None = None
remove_all_tags: bool | None = None
remove_tags: list[int] | None = None
remove_all_correspondents: bool | None = None
remove_correspondents: list[int] | None = None
remove_all_document_types: bool | None = None
remove_document_types: list[int] | None = None
remove_all_storage_paths: bool | None = None
remove_storage_paths: list[int] | None = None
remove_custom_fields: list[int] | None = None
remove_all_custom_fields: bool | None = None
remove_all_owners: bool | None = None
remove_all_permissions: bool | None = None
remove_view_users: list[int] | None = None
remove_view_groups: list[int] | None = None
remove_change_users: list[int] | None = None
remove_change_groups: list[int] | None = None
email: int | None = None
webhook: dict[str, Any] | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Workflow` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class WorkflowTrigger(PaperlessModel, models.MatchingFieldsMixin):
"""Represent a Paperless `WorkflowTrigger`."""
_api_path = API_PATH["workflow_triggers_single"]
id: int | None = None
sources: list[WorkflowTriggerSourceType] | None = None
type: WorkflowTriggerType | None = None
filter_path: str | None = None
filter_filename: str | None = None
filter_mailrule: int | None = None
filter_has_tags: list[int] | None = None
filter_has_correspondent: int | None = None
filter_has_document_type: int | None = None
schedule_offset_days: int | None = None
schedule_is_recurring: bool | None = None
schedule_recurring_interval_days: int | None = None
schedule_date_field: str | None = None
schedule_date_custom_field: int | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Workflow` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
@dataclass(init=False)
class Workflow(PaperlessModel):
"""Represent a Paperless `Workflow`."""
_api_path = API_PATH["workflows_single"]
id: int | None = None
name: str | None = None
order: int | None = None
enabled: bool | None = None
actions: list[WorkflowAction] | None = None
triggers: list[WorkflowTrigger] | None = None
def __init__(self, api: "Paperless", data: dict[str, Any]) -> None:
"""Initialize a `Workflow` instance."""
super().__init__(api, data)
self._api_path = self._api_path.format(pk=data.get("id"))
class WorkflowActionHelper(
HelperBase,
helpers.CallableMixin[WorkflowAction],
helpers.IterableMixin[WorkflowAction],
):
"""Represent a factory for Paperless `WorkflowAction` models."""
_api_path = API_PATH["workflow_actions"]
_resource = PaperlessResource.WORKFLOW_ACTIONS
_resource_cls = WorkflowAction
class WorkflowTriggerHelper(
HelperBase,
helpers.CallableMixin[WorkflowTrigger],
helpers.IterableMixin[WorkflowTrigger],
):
"""Represent a factory for Paperless `WorkflowTrigger` models."""
_api_path = API_PATH["workflow_triggers"]
_resource = PaperlessResource.WORKFLOW_TRIGGERS
_resource_cls = WorkflowTrigger
class WorkflowHelper(
HelperBase,
helpers.CallableMixin[Workflow],
helpers.IterableMixin[Workflow],
):
"""Represent a factory for Paperless `Workflow` models."""
_api_path = API_PATH["workflows"]
_resource = PaperlessResource.WORKFLOWS
_resource_cls = Workflow
def __init__(self, api: "Paperless") -> None:
"""Initialize a `WorkflowHelper` instance."""
super().__init__(api)
self._actions = WorkflowActionHelper(api)
self._triggers = WorkflowTriggerHelper(api)
@property
def actions(self) -> WorkflowActionHelper:
"""Return the attached `WorkflowActionHelper` instance.
Example:
-------
```python
wf_action = await paperless.workflows.actions(5)
```
"""
return self._actions
@property
def triggers(self) -> WorkflowTriggerHelper:
"""Return the attached `WorkflowTriggerHelper` instance.
Example:
-------
```python
wf_trigger = await paperless.workflows.triggers(23)
```
"""
return self._triggers
paperless-api-5.1.0/pypaperless/py.typed 0000664 0000000 0000000 00000000000 15053074171 0020321 0 ustar 00root root 0000000 0000000 paperless-api-5.1.0/pyproject.toml 0000664 0000000 0000000 00000006731 15053074171 0017210 0 ustar 00root root 0000000 0000000 [build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "pypaperless"
version = "0.0.0"
license = {text = "MIT"}
description = "Little api client for paperless(-ngx)."
readme = "README.md"
authors = [
{name = "Tobias Schulz", email = "public.dev@tbsch.de"}
]
keywords = ["library", "async", "api-client", "python3", "paperless-ngx"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Framework :: AsyncIO",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules"
]
requires-python = ">=3.13, <3.14"
dependencies = [
"aiohttp>=3.12.15",
"yarl>=1.20.1",
]
[dependency-groups]
dev = [
"aioresponses>=0.7.8",
"codespell>=2.4.1",
"covdefaults>=2.3.0",
"coverage>=7.10.5",
"mypy>=1.17.1",
"pre-commit>=4.3.0",
"pre-commit-hooks>=6.0.0",
"pylint>=3.3.8",
"pytest>=8.4.1",
"pytest-aiohttp>=1.1.0",
"pytest-asyncio>=1.1.0",
"pytest-cov>=6.2.1",
"ruff>=0.12.10",
"yamllint>=1.37.1",
]
[project.urls]
"Homepage" = "https://github.com/tb1337/paperless-api"
"Source Code" = "https://github.com/tb1337/paperless-api"
"Bug Reports" = "https://github.com/tb1337/paperless-api/issues"
"Coverage" = "https://codecov.io/gh/tb1337/paperless-api"
[tool.coverage.run]
plugins = ["covdefaults"]
source = ["pypaperless"]
[tool.coverage.report]
fail_under = 95
omit = [
"pypaperless/models/utils/__init__.py"
]
show_missing = true
[tool.mypy]
platform = "linux"
python_version = "3.13"
follow_imports = "normal"
ignore_missing_imports = true
check_untyped_defs = true
disallow_any_generics = false
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
show_error_codes = true
warn_incomplete_stub = true
warn_no_return = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
warn_unused_configs = true
warn_unused_ignores = true
[tool.pylint.MASTER]
ignore = [
"tests/",
]
[tool.pylint.BASIC]
good-names = [
"_",
"ex",
"fp",
"i",
"id",
"j",
"k",
"on",
"Run",
"T",
"wv",
]
[tool.pylint."MESSAGES CONTROL"]
disable = [
"duplicate-code",
"no-name-in-module", # currently throws
"too-few-public-methods",
"too-many-ancestors",
"too-many-arguments",
"too-many-instance-attributes",
"too-many-public-methods",
]
[tool.pylint.SIMILARITIES]
ignore-imports = true
[tool.pylint.FORMAT]
max-line-length = 100
[tool.pylint.DESIGN]
max-attributes = 20
[tool.pytest.ini_options]
addopts = "--cov --cov-report=term --cov-report=xml"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
[tool.ruff]
line-length = 100
target-version = "py313"
[tool.ruff.lint]
ignore = [
"ANN401", # Opinioated warning on disallowing dynamically typed expressions
"D203", # Conflicts with other rules
"D213", # Conflicts with other rules
"D417", # False positives in some occasions
"PLR2004", # Just annoying, not really useful
"RUF012", # Just annoying
# Conflicts with the Ruff formatter
"COM812",
"ISC001",
]
select = ["ALL"]
[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false
mark-parentheses = false
[tool.ruff.lint.isort]
known-first-party = ["pypaperless"]
[tool.ruff.lint.mccabe]
max-complexity = 25
paperless-api-5.1.0/script/ 0000775 0000000 0000000 00000000000 15053074171 0015571 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/script/bootstrap 0000775 0000000 0000000 00000000326 15053074171 0017535 0 ustar 00root root 0000000 0000000 #!/bin/sh
# Resolve all dependencies that the application requires to run.
# Stop on errors
set -e
cd "$(dirname "$0")/.."
uv venv $VIRTUAL_ENV
echo "Installing development dependencies..."
uv sync --group dev
paperless-api-5.1.0/script/setup 0000775 0000000 0000000 00000001207 15053074171 0016657 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
# Setups the repository.
# Stop on errors
set -e
cd "$(dirname "$0")/.."
# Add default vscode settings if not existing
SETTINGS_FILE=./.vscode/settings.json
SETTINGS_TEMPLATE_FILE=./.vscode/settings.default.json
if [ ! -f "$SETTINGS_FILE" ]; then
echo "Copy $SETTINGS_TEMPLATE_FILE to $SETTINGS_FILE."
cp "$SETTINGS_TEMPLATE_FILE" "$SETTINGS_FILE"
fi
if [ ! -n "$VIRTUAL_ENV" ]; then
if [ -x "$(command -v uv)" ]; then
uv venv .venv
else
python3 -m venv .venv
fi
source .venv/bin/activate
fi
if ! [ -x "$(command -v uv)" ]; then
python3 -m pip install uv
fi
script/bootstrap
pre-commit install
paperless-api-5.1.0/tests/ 0000775 0000000 0000000 00000000000 15053074171 0015427 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/tests/__init__.py 0000664 0000000 0000000 00000010763 15053074171 0017547 0 ustar 00root root 0000000 0000000 """Tests for pypaperless."""
from dataclasses import dataclass
from typing import Any
from pypaperless import helpers, models
from pypaperless.const import PaperlessResource
from pypaperless.models import common
from .data import (
DATA_CONFIG,
DATA_CORRESPONDENTS,
DATA_CUSTOM_FIELDS,
DATA_DOCUMENT_TYPES,
DATA_DOCUMENTS,
DATA_GROUPS,
DATA_MAIL_ACCOUNTS,
DATA_MAIL_RULES,
DATA_SAVED_VIEWS,
DATA_SHARE_LINKS,
DATA_STATUS,
DATA_STORAGE_PATHS,
DATA_TAGS,
DATA_TASKS,
DATA_USERS,
DATA_WORKFLOWS,
)
# mypy: ignore-errors
@dataclass
class ResourceTestMapping:
"""Mapping for test cases."""
resource: str
data: dict[str, Any] | list[dict[str, Any]]
helper_cls: type
model_cls: type
draft_cls: type | None = None
draft_defaults: dict[str, Any] | None = None
CONFIG_MAP = ResourceTestMapping(
PaperlessResource.CONFIG,
DATA_CONFIG,
helpers.ConfigHelper,
models.Config,
)
CORRESPONDENT_MAP = ResourceTestMapping(
PaperlessResource.CORRESPONDENTS,
DATA_CORRESPONDENTS,
helpers.CorrespondentHelper,
models.Correspondent,
models.CorrespondentDraft,
{
"name": "New Correspondent",
"match": "",
"matching_algorithm": common.MatchingAlgorithmType.ANY,
"is_insensitive": True,
},
)
CUSTOM_FIELD_MAP = ResourceTestMapping(
PaperlessResource.CUSTOM_FIELDS,
DATA_CUSTOM_FIELDS,
helpers.CustomFieldHelper,
models.CustomField,
models.CustomFieldDraft,
{
"name": "New Custom Field",
"data_type": common.CustomFieldType.BOOLEAN,
},
)
DOCUMENT_MAP = ResourceTestMapping(
PaperlessResource.DOCUMENTS,
DATA_DOCUMENTS,
helpers.DocumentHelper,
models.Document,
models.DocumentDraft,
{
"document": b"...example...content...",
"tags": [1, 2, 3],
"correspondent": 1,
"document_type": 1,
"storage_path": 1,
"title": "New Document",
"created": None,
"archive_serial_number": 1,
},
)
DOCUMENT_TYPE_MAP = ResourceTestMapping(
PaperlessResource.DOCUMENT_TYPES,
DATA_DOCUMENT_TYPES,
helpers.DocumentTypeHelper,
models.DocumentType,
models.DocumentTypeDraft,
{
"name": "New Document Type",
"match": "",
"matching_algorithm": common.MatchingAlgorithmType.ANY,
"is_insensitive": True,
},
)
GROUP_MAP = ResourceTestMapping(
PaperlessResource.GROUPS,
DATA_GROUPS,
helpers.GroupHelper,
models.Group,
)
MAIL_ACCOUNT_MAP = ResourceTestMapping(
PaperlessResource.MAIL_ACCOUNTS,
DATA_MAIL_ACCOUNTS,
helpers.MailAccountHelper,
models.MailAccount,
)
MAIL_RULE_MAP = ResourceTestMapping(
PaperlessResource.MAIL_RULES,
DATA_MAIL_RULES,
helpers.MailRuleHelper,
models.MailRule,
)
SAVED_VIEW_MAP = ResourceTestMapping(
PaperlessResource.SAVED_VIEWS,
DATA_SAVED_VIEWS,
helpers.SavedViewHelper,
models.SavedView,
)
SHARE_LINK_MAP = ResourceTestMapping(
PaperlessResource.SHARE_LINKS,
DATA_SHARE_LINKS,
helpers.ShareLinkHelper,
models.ShareLink,
models.ShareLinkDraft,
{
"expiration": None,
"document": 1,
"file_version": common.ShareLinkFileVersionType.ORIGINAL,
},
)
STATUS_MAP = ResourceTestMapping(
PaperlessResource.STATUS,
DATA_STATUS,
helpers.StatusHelper,
models.Status,
)
STORAGE_PATH_MAP = ResourceTestMapping(
PaperlessResource.STORAGE_PATHS,
DATA_STORAGE_PATHS,
helpers.StoragePathHelper,
models.StoragePath,
models.StoragePathDraft,
{
"name": "New Storage Path",
"path": "path/to/test",
"match": "",
"matching_algorithm": common.MatchingAlgorithmType.ANY,
"is_insensitive": True,
},
)
TAG_MAP = ResourceTestMapping(
PaperlessResource.TAGS,
DATA_TAGS,
helpers.TagHelper,
models.Tag,
models.TagDraft,
{
"name": "New Tag",
"color": "#012345",
"text_color": "#987654",
"is_inbox_tag": False,
"match": "",
"matching_algorithm": common.MatchingAlgorithmType.ANY,
"is_insensitive": True,
},
)
TASK_MAP = ResourceTestMapping(
PaperlessResource.TASKS,
DATA_TASKS,
helpers.TaskHelper,
models.Task,
)
USER_MAP = ResourceTestMapping(
PaperlessResource.USERS,
DATA_USERS,
helpers.UserHelper,
models.User,
)
WORKFLOW_MAP = ResourceTestMapping(
PaperlessResource.WORKFLOWS,
DATA_WORKFLOWS,
helpers.WorkflowHelper,
models.Workflow,
)
paperless-api-5.1.0/tests/conftest.py 0000664 0000000 0000000 00000002142 15053074171 0017625 0 ustar 00root root 0000000 0000000 """Setup pytest."""
from collections.abc import AsyncGenerator, Generator
from typing import Any
import pytest
from aioresponses import aioresponses
from pypaperless import Paperless
from pypaperless.const import API_PATH
from .const import PAPERLESS_TEST_REQ_ARGS, PAPERLESS_TEST_TOKEN, PAPERLESS_TEST_URL
from .data import DATA_SCHEMA
# mypy: ignore-errors
@pytest.fixture(name="resp")
def aioresponses_fixture() -> Generator[aioresponses]:
"""Return aioresponses fixture."""
with aioresponses() as m:
yield m
@pytest.fixture(name="api")
def api_obj_fixture() -> Paperless:
"""Return Paperless."""
return Paperless(
PAPERLESS_TEST_URL,
PAPERLESS_TEST_TOKEN,
request_args=PAPERLESS_TEST_REQ_ARGS,
)
@pytest.fixture(name="paperless")
async def paperless_fixture(
resp: aioresponses,
api: Paperless,
) -> AsyncGenerator[Paperless, Any]:
"""Return a Paperless object with given version."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=200,
payload=DATA_SCHEMA,
)
async with api:
yield api
paperless-api-5.1.0/tests/const.py 0000664 0000000 0000000 00000000376 15053074171 0017135 0 ustar 00root root 0000000 0000000 """Test constants."""
PAPERLESS_TEST_URL = "https://paperless.not-existing.internal"
PAPERLESS_TEST_TOKEN = "abcdef0123456789"
PAPERLESS_TEST_USER = "test-user"
PAPERLESS_TEST_PASSWORD = "not-so-secret-password"
PAPERLESS_TEST_REQ_ARGS = {"ssl": False}
paperless-api-5.1.0/tests/data/ 0000775 0000000 0000000 00000000000 15053074171 0016340 5 ustar 00root root 0000000 0000000 paperless-api-5.1.0/tests/data/__init__.py 0000664 0000000 0000000 00000003755 15053074171 0020463 0 ustar 00root root 0000000 0000000 """Raw data constants."""
import json
from pathlib import Path
from .config import DATA_CONFIG
from .correspondents import DATA_CORRESPONDENTS
from .custom_fields import DATA_CUSTOM_FIELDS
from .document_metadata import DATA_DOCUMENT_METADATA
from .document_notes import DATA_DOCUMENT_NOTES
from .document_suggestions import DATA_DOCUMENT_SUGGESTIONS
from .document_types import DATA_DOCUMENT_TYPES
from .documents import DATA_DOCUMENTS
from .documents_search import DATA_DOCUMENTS_SEARCH
from .groups import DATA_GROUPS
from .mail import DATA_MAIL_ACCOUNTS, DATA_MAIL_RULES
from .object_permissions import DATA_OBJECT_PERMISSIONS
from .paths import DATA_PATHS
from .remote_version import DATA_REMOTE_VERSION
from .saved_views import DATA_SAVED_VIEWS
from .share_links import DATA_SHARE_LINKS
from .statistics import DATA_STATISTICS
from .status import DATA_STATUS
from .storage_paths import DATA_STORAGE_PATHS
from .tags import DATA_TAGS
from .tasks import DATA_TASKS
from .token import DATA_TOKEN
from .users import DATA_USERS
from .workflow import DATA_WORKFLOW_ACTIONS, DATA_WORKFLOW_TRIGGERS, DATA_WORKFLOWS
# mypy: ignore-errors
def _read_schema() -> dict:
filepath = Path("tests/data/schema.json")
with Path.open(filepath, mode="r", encoding="utf-8") as file:
return json.load(file)
DATA_SCHEMA = _read_schema()
__all__ = (
"DATA_CONFIG",
"DATA_CORRESPONDENTS",
"DATA_CUSTOM_FIELDS",
"DATA_DOCUMENTS",
"DATA_DOCUMENTS_SEARCH",
"DATA_DOCUMENT_METADATA",
"DATA_DOCUMENT_NOTES",
"DATA_DOCUMENT_SUGGESTIONS",
"DATA_DOCUMENT_TYPES",
"DATA_GROUPS",
"DATA_MAIL_ACCOUNTS",
"DATA_MAIL_RULES",
"DATA_OBJECT_PERMISSIONS",
"DATA_PATHS",
"DATA_REMOTE_VERSION",
"DATA_SAVED_VIEWS",
"DATA_SCHEMA",
"DATA_SHARE_LINKS",
"DATA_STATISTICS",
"DATA_STATUS",
"DATA_STORAGE_PATHS",
"DATA_TAGS",
"DATA_TASKS",
"DATA_TOKEN",
"DATA_USERS",
"DATA_WORKFLOWS",
"DATA_WORKFLOW_ACTIONS",
"DATA_WORKFLOW_TRIGGERS",
)
paperless-api-5.1.0/tests/data/config.py 0000664 0000000 0000000 00000001005 15053074171 0020153 0 ustar 00root root 0000000 0000000 """Config snapshot."""
DATA_CONFIG = [
{
"id": 1,
"user_args": None,
"output_type": "pdf",
"pages": None,
"language": "eng",
"mode": None,
"skip_archive_file": None,
"image_dpi": None,
"unpaper_clean": None,
"deskew": None,
"rotate_pages": None,
"rotate_pages_threshold": None,
"max_image_pixels": None,
"color_conversion_strategy": None,
"app_title": None,
"app_logo": None,
}
]
paperless-api-5.1.0/tests/data/correspondents.py 0000664 0000000 0000000 00000004100 15053074171 0021755 0 ustar 00root root 0000000 0000000 """Correspondents snapshot."""
DATA_CORRESPONDENTS = {
"count": 5,
"next": None,
"previous": None,
"all": [1, 2, 3, 4, 5],
"results": [
{
"id": 1,
"slug": "sample-correspondent",
"name": "Sample Correspondent",
"match": "",
"matching_algorithm": 1,
"is_insensitive": True,
"document_count": 12,
"last_correspondence": "2022-10-18",
"owner": None,
"user_can_change": True,
},
{
"id": 2,
"slug": "burger-fastfood-delivery-billing",
"name": "Burger FastFood Delivery Billing",
"match": "",
"matching_algorithm": 1,
"is_insensitive": True,
"document_count": 6,
"last_correspondence": "2006-03-07",
"owner": None,
"user_can_change": True,
},
{
"id": 3,
"slug": "example-company",
"name": "Example Company",
"match": "",
"matching_algorithm": 6,
"is_insensitive": True,
"document_count": 3,
"last_correspondence": "2022-03-11",
"owner": 3,
"user_can_change": True,
},
{
"id": 4,
"slug": "no-illness-more-money-health-insurance",
"name": "No Illness More Money Health Insurance",
"match": "",
"matching_algorithm": 1,
"is_insensitive": True,
"document_count": 6,
"last_correspondence": "2000-07-18",
"owner": None,
"user_can_change": True,
},
{
"id": 5,
"slug": "your-cash-is-my-cash-bank",
"name": "Your Cash is my Cash Bank",
"match": "Your Cash My Bank",
"matching_algorithm": 2,
"is_insensitive": True,
"document_count": 20,
"last_correspondence": "2023-08-28",
"owner": None,
"user_can_change": True,
},
],
}
paperless-api-5.1.0/tests/data/custom_fields.py 0000664 0000000 0000000 00000001311 15053074171 0021546 0 ustar 00root root 0000000 0000000 """Custom fields snapshot."""
DATA_CUSTOM_FIELDS = {
"count": 8,
"next": None,
"previous": None,
"all": [8, 7, 6, 5, 4, 3, 2, 1],
"results": [
{"id": 8, "name": "Custom Link", "data_type": "documentlink"},
{"id": 7, "name": "Custom URL", "data_type": "url"},
{"id": 6, "name": "Custom Text -added-", "data_type": "string"},
{"id": 5, "name": "Custom MONEYY $$$", "data_type": "monetary"},
{"id": 4, "name": "Custom Floating", "data_type": "float"},
{"id": 3, "name": "Custom Int", "data_type": "integer"},
{"id": 2, "name": "Custom Date", "data_type": "date"},
{"id": 1, "name": "Custom Bool", "data_type": "boolean"},
],
}
paperless-api-5.1.0/tests/data/document_metadata.py 0000664 0000000 0000000 00000004765 15053074171 0022404 0 ustar 00root root 0000000 0000000 """Document metadata snapshot."""
DATA_DOCUMENT_METADATA = {
"original_checksum": "18e2352cc13379d19bd9ce329428bb99",
"original_size": 190348,
"original_mime_type": "application/pdf",
"media_filename": "xxx.pdf",
"has_archive_version": True,
"original_metadata": [],
"archive_checksum": "8a69542583571337dd263f8bb3cf23bd",
"archive_media_filename": "0000226.pdf",
"original_filename": None,
"lang": "de",
"archive_size": 161371,
"archive_metadata": [
{
"namespace": "http://ns.adobe.com/pdf/1.3/",
"prefix": "pdf",
"key": "Producer",
"value": "pikepdf 2.16.1",
},
{
"namespace": "http://ns.adobe.com/xap/1.0/",
"prefix": "xmp",
"key": "ModifyDate",
"value": "2022-02-12T11:34:40+00:00",
},
{
"namespace": "http://ns.adobe.com/xap/1.0/",
"prefix": "xmp",
"key": "CreateDate",
"value": "2022-01-07T13:40:49",
},
{
"namespace": "http://ns.adobe.com/xap/1.0/",
"prefix": "xmp",
"key": "CreatorTool",
"value": "ocrmypdf 12.3.2 / Tesseract OCR-PDF 4.1.1",
},
{
"namespace": "http://ns.adobe.com/xap/1.0/mm/",
"prefix": "xmpMM",
"key": "DocumentID",
"value": "uuid:13371337-2342-1337-4242-133723426665",
},
{
"namespace": "http://purl.org/dc/elements/1.1/",
"prefix": "dc",
"key": "format",
"value": "application/pdf",
},
{
"namespace": "http://purl.org/dc/elements/1.1/",
"prefix": "dc",
"key": "title",
"value": "Octopus Energy updated",
},
{
"namespace": "http://www.aiim.org/pdfa/ns/id/",
"prefix": "pdfaid",
"key": "part",
"value": "2",
},
{
"namespace": "http://www.aiim.org/pdfa/ns/id/",
"prefix": "pdfaid",
"key": "conformance",
"value": "B",
},
{
"namespace": "http://purl.org/dc/elements/1.1/",
"prefix": "dc",
"key": "creator",
"value": "None",
},
{
"namespace": "http://ns.adobe.com/xap/1.0/",
"prefix": "xmp",
"key": "MetadataDate",
"value": "2022-02-12T11:34:40.383718+00:00",
},
],
}
paperless-api-5.1.0/tests/data/document_notes.py 0000664 0000000 0000000 00000001544 15053074171 0021744 0 ustar 00root root 0000000 0000000 """Document notes snapshot."""
DATA_DOCUMENT_NOTES = [
{
"id": 1,
"note": "Sample note 1.",
"created": "2023-12-21T18:08:11.481206+00:00",
"user": {
"id": 1,
"username": "test",
"first_name": "Peter",
"last_name": "Patch",
},
},
{
"id": 2,
"note": "Sample note 2.",
"created": "2023-12-21T08:26:33.260968+00:00",
"user": {
"id": 2,
"username": "test",
"first_name": "Peter",
"last_name": "Patch",
},
},
{
"id": 3,
"note": "Sample note 3.",
"created": "2023-12-21T08:26:31.782811+00:00",
"user": {
"id": 3,
"username": "test",
"first_name": "Peter",
"last_name": "Patch",
},
},
]
paperless-api-5.1.0/tests/data/document_suggestions.py 0000664 0000000 0000000 00000000451 15053074171 0023162 0 ustar 00root root 0000000 0000000 """Document suggestions snapshot."""
DATA_DOCUMENT_SUGGESTIONS = {
"correspondents": [26],
"tags": [
1,
2,
3,
],
"document_types": [4],
"storage_paths": [
3,
5,
],
"dates": [
"2022-01-07",
"2023-01-07",
],
}
paperless-api-5.1.0/tests/data/document_types.py 0000664 0000000 0000000 00000003230 15053074171 0021752 0 ustar 00root root 0000000 0000000 """Document types snapshot."""
DATA_DOCUMENT_TYPES = {
"count": 5,
"next": None,
"previous": None,
"all": [1, 2, 3, 4, 5],
"results": [
{
"id": 1,
"slug": "bescheid",
"name": "Bescheid",
"match": "",
"matching_algorithm": 1,
"is_insensitive": True,
"document_count": 42,
"owner": None,
"user_can_change": True,
},
{
"id": 2,
"slug": "document",
"name": "Document",
"match": "",
"matching_algorithm": 1,
"is_insensitive": True,
"document_count": 218,
"owner": None,
"user_can_change": None,
},
{
"id": 3,
"slug": "kontoauszug",
"name": "Kontoauszug",
"match": "",
"matching_algorithm": 6,
"is_insensitive": True,
"document_count": 227,
"owner": None,
"user_can_change": None,
},
{
"id": 4,
"slug": "kundigung",
"name": "Kuendigung",
"match": "",
"matching_algorithm": 1,
"is_insensitive": True,
"document_count": 24,
"owner": None,
"user_can_change": True,
},
{
"id": 5,
"slug": "rechnung",
"name": "Rechnung",
"match": "",
"matching_algorithm": 6,
"is_insensitive": True,
"document_count": 246,
"owner": None,
"user_can_change": True,
},
],
}
paperless-api-5.1.0/tests/data/documents.py 0000664 0000000 0000000 00000005140 15053074171 0020713 0 ustar 00root root 0000000 0000000 """Documents snapshot."""
DATA_DOCUMENTS = {
"count": 2,
"next": None,
"previous": "",
"all": [1, 2],
"results": [
{
"id": 1,
"correspondent": 1,
"document_type": 2,
"storage_path": None,
"title": "Crazy Document",
"content": "some OCRd text",
"tags": [],
"created": "2011-06-22",
"modified": "2023-08-08T06:06:35.495972+00:00",
"added": "2023-06-30T05:44:14.317925+00:00",
"archive_serial_number": None,
"original_file_name": "Scan_2023-06-29_113857.pdf",
"archived_file_name": "2011-06-22 filename.pdf",
"owner": 2,
"user_can_change": True,
"notes": [],
"custom_fields": [],
},
{
"id": 2,
"correspondent": 2,
"document_type": 1,
"storage_path": 1,
"title": "Salty Document",
"content": "OCRd text from document",
"tags": [1],
"created": "2022-01-07",
"modified": "2023-12-13T16:15:02.148852+00:00",
"added": "2022-02-12T11:34:50.072000+00:00",
"archive_serial_number": 1,
"original_file_name": None,
"archived_file_name": "2022-01-07.pdf",
"owner": 1,
"user_can_change": True,
"notes": [
{
"id": 1,
"note": "Sample note 1.",
"created": "2023-12-21T18:08:11.481206+00:00",
"document": 2,
"user": 1,
},
{
"id": 2,
"note": "Sample note 2.",
"created": "2023-12-21T08:26:33.260968+00:00",
"document": 2,
"user": 2,
},
{
"id": 3,
"note": "Sample note 3.",
"created": "2023-12-21T08:26:31.782811+00:00",
"document": 2,
"user": 3,
},
],
"custom_fields": [
{"value": [1094, 944], "field": 8},
{"value": "https://www.example.com", "field": 7},
{"value": "This is a text", "field": 6},
{"value": 1000.0, "field": 5},
{"value": 13.37, "field": 4},
{"value": 42, "field": 3},
{"value": "2099-12-31", "field": 2},
{"value": True, "field": 1},
],
},
],
}
paperless-api-5.1.0/tests/data/documents_search.py 0000664 0000000 0000000 00000002132 15053074171 0022236 0 ustar 00root root 0000000 0000000 """Documents search snapshot."""
# mypy: ignore-errors
DATA_DOCUMENTS_SEARCH = {
"count": 1,
"next": None,
"previous": None,
"all": [1],
"results": [
{
"id": 1,
"correspondent": 1,
"document_type": 2,
"storage_path": None,
"title": "Crazy Document",
"content": "some OCRd text",
"tags": [],
"created": "2011-06-22T00:00:00+00:00",
"created_date": "2011-06-22",
"modified": "2023-08-08T06:06:35.495972+00:00",
"added": "2023-06-30T05:44:14.317925+00:00",
"archive_serial_number": None,
"original_file_name": "Scan_2023-06-29_113857.pdf",
"archived_file_name": "2011-06-22 filename.pdf",
"owner": 2,
"user_can_change": True,
"notes": [],
"custom_fields": [],
"__search_hit__": {
"score": 1.0,
"highlights": "some neat hint",
"note_highlights": "",
"rank": 0,
},
},
],
}
paperless-api-5.1.0/tests/data/groups.py 0000664 0000000 0000000 00000003007 15053074171 0020231 0 ustar 00root root 0000000 0000000 """Groups snapshot."""
DATA_GROUPS = {
"count": 1,
"next": None,
"previous": None,
"all": [1],
"results": [
{
"id": 1,
"name": "Sample Group",
"permissions": [
"add_consumptiontemplate",
"change_consumptiontemplate",
"delete_consumptiontemplate",
"view_consumptiontemplate",
"view_correspondent",
"add_customfield",
"change_customfield",
"delete_customfield",
"view_customfield",
"add_customfieldinstance",
"change_customfieldinstance",
"delete_customfieldinstance",
"view_customfieldinstance",
"add_document",
"change_document",
"delete_document",
"view_document",
"view_documenttype",
"add_note",
"change_note",
"delete_note",
"view_note",
"add_savedview",
"change_savedview",
"delete_savedview",
"view_savedview",
"add_sharelink",
"change_sharelink",
"delete_sharelink",
"view_sharelink",
"view_tag",
"add_uisettings",
"change_uisettings",
"delete_uisettings",
"view_uisettings",
],
},
],
}
paperless-api-5.1.0/tests/data/mail.py 0000664 0000000 0000000 00000003013 15053074171 0017631 0 ustar 00root root 0000000 0000000 """Mail snapshots."""
# mypy: ignore-errors
DATA_MAIL_ACCOUNTS = {
"count": 1,
"next": None,
"previous": None,
"all": [1],
"results": [
{
"id": 1,
"name": "Test Account",
"imap_server": "imap.omega.net",
"imap_port": 1337,
"imap_security": 2,
"username": "omega-weapon",
"password": "********************",
"character_set": "UTF-8",
"is_token": False,
"owner": 1,
"user_can_change": True,
}
],
}
DATA_MAIL_RULES = {
"count": 1,
"next": None,
"previous": None,
"all": [1],
"results": [
{
"id": 1,
"name": "Test",
"account": 1,
"folder": "INBOX",
"filter_from": None,
"filter_to": None,
"filter_subject": None,
"filter_body": None,
"filter_attachment_filename_include": None,
"filter_attachment_filename_exclude": None,
"maximum_age": 3,
"action": 3,
"action_parameter": None,
"assign_title_from": 1,
"assign_tags": [],
"assign_correspondent_from": 1,
"assign_correspondent": None,
"assign_document_type": None,
"assign_owner_from_rule": True,
"order": 1,
"attachment_type": 1,
"consumption_scope": 1,
"owner": 1,
"user_can_change": True,
}
],
}
paperless-api-5.1.0/tests/data/object_permissions.py 0000664 0000000 0000000 00000000311 15053074171 0022606 0 ustar 00root root 0000000 0000000 """Object permissions snapshot."""
DATA_OBJECT_PERMISSIONS = {
"view": {
"users": [1, 2],
"groups": [],
},
"change": {
"users": [],
"groups": [1],
},
}
paperless-api-5.1.0/tests/data/paths.py 0000664 0000000 0000000 00000002172 15053074171 0020033 0 ustar 00root root 0000000 0000000 """Paths snapshot."""
from tests.const import PAPERLESS_TEST_URL
DATA_PATHS = {
"correspondents": f"{PAPERLESS_TEST_URL}/api/correspondents/",
"document_types": f"{PAPERLESS_TEST_URL}/api/document_types/",
"documents": f"{PAPERLESS_TEST_URL}/api/documents/",
"logs": f"{PAPERLESS_TEST_URL}/api/logs/",
"tags": f"{PAPERLESS_TEST_URL}/api/tags/",
"saved_views": f"{PAPERLESS_TEST_URL}/api/saved_views/",
"tasks": f"{PAPERLESS_TEST_URL}/api/tasks/",
"users": f"{PAPERLESS_TEST_URL}/api/users/",
"groups": f"{PAPERLESS_TEST_URL}/api/groups/",
"mail_accounts": f"{PAPERLESS_TEST_URL}/api/mail_accounts/",
"mail_rules": f"{PAPERLESS_TEST_URL}/api/mail_rules/",
"storage_paths": f"{PAPERLESS_TEST_URL}/api/storage_paths/",
"config": f"{PAPERLESS_TEST_URL}/api/config/",
"custom_fields": f"{PAPERLESS_TEST_URL}/api/custom_fields/",
"share_links": f"{PAPERLESS_TEST_URL}/api/share_links/",
"workflows": f"{PAPERLESS_TEST_URL}/api/workflows/",
"workflow_actions": f"{PAPERLESS_TEST_URL}/api/workflow_actions/",
"workflow_triggers": f"{PAPERLESS_TEST_URL}/api/workflow_triggers/",
}
paperless-api-5.1.0/tests/data/remote_version.py 0000664 0000000 0000000 00000000147 15053074171 0021754 0 ustar 00root root 0000000 0000000 """Remote version snapshot."""
DATA_REMOTE_VERSION = {"version": "v2.15.3", "update_available": True}
paperless-api-5.1.0/tests/data/saved_views.py 0000664 0000000 0000000 00000003773 15053074171 0021243 0 ustar 00root root 0000000 0000000 """Saved views snapshot."""
DATA_SAVED_VIEWS = {
"count": 5,
"next": None,
"previous": None,
"all": [1, 2, 3, 4, 5],
"results": [
{
"id": 1,
"name": "New Items",
"show_on_dashboard": False,
"show_in_sidebar": False,
"sort_field": None,
"sort_reverse": False,
"filter_rules": [{"rule_type": 6, "value": "1"}],
"owner": 1,
"user_can_change": True,
},
{
"id": 2,
"name": "New Items Alpha",
"show_on_dashboard": True,
"show_in_sidebar": False,
"sort_field": "title",
"sort_reverse": False,
"filter_rules": [
{"rule_type": 6, "value": "1"},
{"rule_type": 33, "value": "7"},
],
"owner": 1,
"user_can_change": True,
},
{
"id": 3,
"name": "New Items Omega",
"show_on_dashboard": True,
"show_in_sidebar": False,
"sort_field": None,
"sort_reverse": False,
"filter_rules": [
{"rule_type": 6, "value": "1"},
{"rule_type": 35, "value": "7"},
],
"owner": 1,
"user_can_change": True,
},
{
"id": 4,
"name": "Tax",
"show_on_dashboard": False,
"show_in_sidebar": True,
"sort_field": "created",
"sort_reverse": True,
"filter_rules": [{"rule_type": 6, "value": "3"}],
"owner": 1,
"user_can_change": True,
},
{
"id": 5,
"name": "Todo",
"show_on_dashboard": False,
"show_in_sidebar": True,
"sort_field": "created",
"sort_reverse": True,
"filter_rules": [{"rule_type": 6, "value": "4"}],
"owner": 1,
"user_can_change": True,
},
],
}
paperless-api-5.1.0/tests/data/schema.json 0000664 0000000 0000000 00002142611 15053074171 0020502 0 ustar 00root root 0000000 0000000 {
"openapi": "3.0.3",
"info": {
"title": "Paperless-ngx REST API",
"version": "6.0.0 (9)",
"description": "OpenAPI Spec for Paperless-ngx"
},
"paths": {
"/api/bulk_edit_objects/": {
"post": {
"operationId": "bulk_edit_objects",
"description": "Perform a bulk edit operation on a list of objects",
"externalDocs": {
"description": "Further documentation",
"url": "https://docs.paperless-ngx.com/api/#objects"
},
"tags": [
"bulk_edit_objects"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkEditObjectsRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkEditResult"
}
}
},
"description": ""
}
}
}
},
"/api/config/": {
"get": {
"operationId": "config_list",
"description": "Get the application configuration",
"externalDocs": {
"description": "Application Configuration",
"url": "https://docs.paperless-ngx.com/configuration/"
},
"tags": [
"config"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ApplicationConfiguration"
}
}
}
},
"description": ""
}
}
}
},
"/api/config/{id}/": {
"get": {
"operationId": "config_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this paperless application settings.",
"required": true
}
],
"tags": [
"config"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationConfiguration"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "config_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this paperless application settings.",
"required": true
}
],
"tags": [
"config"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationConfigurationRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/ApplicationConfigurationRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/ApplicationConfigurationRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationConfiguration"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "config_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this paperless application settings.",
"required": true
}
],
"tags": [
"config"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedApplicationConfigurationRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedApplicationConfigurationRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedApplicationConfigurationRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationConfiguration"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "config_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this paperless application settings.",
"required": true
}
],
"tags": [
"config"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/correspondents/": {
"get": {
"operationId": "correspondents_list",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__istartswith",
"schema": {
"type": "string"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"correspondents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedCorrespondentList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "correspondents_create",
"tags": [
"correspondents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CorrespondentRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/CorrespondentRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/CorrespondentRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Correspondent"
}
}
},
"description": ""
}
}
}
},
"/api/correspondents/{id}/": {
"get": {
"operationId": "correspondents_retrieve",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this correspondent.",
"required": true
}
],
"tags": [
"correspondents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Correspondent"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "correspondents_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this correspondent.",
"required": true
}
],
"tags": [
"correspondents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CorrespondentRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/CorrespondentRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/CorrespondentRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Correspondent"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "correspondents_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this correspondent.",
"required": true
}
],
"tags": [
"correspondents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedCorrespondentRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedCorrespondentRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedCorrespondentRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Correspondent"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "correspondents_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this correspondent.",
"required": true
}
],
"tags": [
"correspondents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/custom_fields/": {
"get": {
"operationId": "custom_fields_list",
"parameters": [
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__istartswith",
"schema": {
"type": "string"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"custom_fields"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedCustomFieldList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "custom_fields_create",
"tags": [
"custom_fields"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomFieldRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/CustomFieldRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/CustomFieldRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomField"
}
}
},
"description": ""
}
}
}
},
"/api/custom_fields/{id}/": {
"get": {
"operationId": "custom_fields_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this custom field.",
"required": true
}
],
"tags": [
"custom_fields"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomField"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "custom_fields_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this custom field.",
"required": true
}
],
"tags": [
"custom_fields"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomFieldRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/CustomFieldRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/CustomFieldRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomField"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "custom_fields_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this custom field.",
"required": true
}
],
"tags": [
"custom_fields"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedCustomFieldRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedCustomFieldRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedCustomFieldRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomField"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "custom_fields_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this custom field.",
"required": true
}
],
"tags": [
"custom_fields"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/document_types/": {
"get": {
"operationId": "document_types_list",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__istartswith",
"schema": {
"type": "string"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"document_types"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedDocumentTypeList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "document_types_create",
"tags": [
"document_types"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentTypeRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/DocumentTypeRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/DocumentTypeRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentType"
}
}
},
"description": ""
}
}
}
},
"/api/document_types/{id}/": {
"get": {
"operationId": "document_types_retrieve",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document type.",
"required": true
}
],
"tags": [
"document_types"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentType"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "document_types_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document type.",
"required": true
}
],
"tags": [
"document_types"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentTypeRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/DocumentTypeRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/DocumentTypeRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentType"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "document_types_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document type.",
"required": true
}
],
"tags": [
"document_types"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedDocumentTypeRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedDocumentTypeRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedDocumentTypeRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentType"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "document_types_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document type.",
"required": true
}
],
"tags": [
"document_types"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/documents/": {
"get": {
"operationId": "documents_list",
"description": "Document views including search",
"parameters": [
{
"in": "query",
"name": "added__date__gt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "added__date__gte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "added__date__lt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "added__date__lte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "added__day",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "added__gt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "added__gte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "added__lt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "added__lte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "added__month",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "added__year",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "archive_serial_number",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "archive_serial_number__gt",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "archive_serial_number__gte",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "archive_serial_number__isnull",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "archive_serial_number__lt",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "archive_serial_number__lte",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "checksum__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "checksum__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "checksum__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "checksum__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "content__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "content__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "content__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "content__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "correspondent__id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "correspondent__id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "correspondent__id__none",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "correspondent__isnull",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "correspondent__name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "correspondent__name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "correspondent__name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "correspondent__name__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "created__date__gt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__date__gte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__date__lt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__date__lte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__day",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "created__gt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__gte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__lt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__lte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__month",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "created__year",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "custom_field_query",
"schema": {
"type": "string",
"minLength": 1
}
},
{
"in": "query",
"name": "custom_fields__icontains",
"schema": {
"type": "string",
"minLength": 1
}
},
{
"in": "query",
"name": "custom_fields__id__all",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "custom_fields__id__in",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "custom_fields__id__none",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "document_type__id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "document_type__id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "document_type__id__none",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "document_type__isnull",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "document_type__name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "document_type__name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "document_type__name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "document_type__name__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "fields",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "has_custom_fields",
"schema": {
"type": "boolean"
},
"description": "Has custom field"
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "is_in_inbox",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "is_tagged",
"schema": {
"type": "boolean"
},
"description": "Is tagged"
},
{
"in": "query",
"name": "mime_type",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "modified__date__gt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "modified__date__gte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "modified__date__lt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "modified__date__lte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "modified__day",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "modified__gt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "modified__gte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "modified__lt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "modified__lte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "modified__month",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "modified__year",
"schema": {
"type": "number"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "original_filename__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "original_filename__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "original_filename__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "original_filename__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "owner__id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "owner__id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "owner__id__none",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "owner__isnull",
"schema": {
"type": "boolean"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "query",
"schema": {
"type": "string"
},
"description": "Advanced search query string"
},
{
"name": "search",
"required": false,
"in": "query",
"description": "A search term.",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "shared_by__id",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "storage_path__id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "storage_path__id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "storage_path__id__none",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "storage_path__isnull",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "storage_path__name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "storage_path__name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "storage_path__name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "storage_path__name__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "tags__id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "tags__id__all",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "tags__id__in",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "tags__id__none",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "tags__name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "tags__name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "tags__name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "tags__name__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "title__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "title__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "title__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "title__istartswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "title_content",
"schema": {
"type": "string",
"minLength": 1
}
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedDocumentList"
}
}
},
"description": ""
}
}
}
},
"/api/documents/{id}/": {
"get": {
"operationId": "documents_retrieve",
"description": "Retrieve a single document",
"parameters": [
{
"in": "query",
"name": "fields",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Document"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
}
}
},
"put": {
"operationId": "documents_update",
"description": "Pass a user object to serializer",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/DocumentRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/DocumentRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Document"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "documents_partial_update",
"description": "Pass a user object to serializer",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedDocumentRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedDocumentRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedDocumentRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Document"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "documents_destroy",
"description": "Pass a user object to serializer",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/documents/{id}/download/": {
"get": {
"operationId": "documents_download_retrieve",
"description": "Download the document",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
},
{
"in": "query",
"name": "original",
"schema": {
"type": "boolean"
}
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string",
"format": "binary"
}
}
},
"description": ""
}
}
}
},
"/api/documents/{id}/email/": {
"post": {
"operationId": "documents_email_create",
"description": "Email the document to one or more recipients as an attachment.",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EmailRequestRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/EmailRequestRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/EmailRequestRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EmailResponse"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
},
"500": {
"description": "No response body"
}
}
}
},
"/api/documents/{id}/history/": {
"get": {
"operationId": "documents_history_list",
"description": "View the document history",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedLogEntryList"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
}
}
}
},
"/api/documents/{id}/metadata/": {
"get": {
"operationId": "documents_metadata_retrieve",
"description": "View the document metadata",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Metadata"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
}
}
}
},
"/api/documents/{id}/notes/": {
"get": {
"operationId": "documents_notes_list",
"description": "View, add, or delete notes for the document",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
},
"description": "Note ID to delete (used only for DELETE requests)"
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedNotesList"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
}
}
},
"post": {
"operationId": "documents_notes_create",
"description": "View, add, or delete notes for the document",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
},
"description": "Note ID to delete (used only for DELETE requests)"
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"documents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NoteCreateRequestRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/NoteCreateRequestRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/NoteCreateRequestRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedNotesList"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
}
}
},
"delete": {
"operationId": "documents_notes_destroy",
"description": "View, add, or delete notes for the document",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
},
"description": "Note ID to delete (used only for DELETE requests)"
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedNotesList"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
}
}
}
},
"/api/documents/{id}/preview/": {
"get": {
"operationId": "documents_preview_retrieve",
"description": "View the document preview",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string",
"format": "binary"
}
}
},
"description": ""
}
}
}
},
"/api/documents/{id}/share_links/": {
"get": {
"operationId": "document_share_links",
"description": "View share links for the document",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "string"
},
"required": true
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"created": {
"type": "string",
"format": "date-time"
},
"expiration": {
"type": "string",
"format": "date-time"
},
"slug": {
"type": "string"
}
}
}
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
}
}
}
},
"/api/documents/{id}/suggestions/": {
"get": {
"operationId": "documents_suggestions_retrieve",
"description": "View suggestions for the document",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Suggestions"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
},
"403": {
"description": "No response body"
},
"404": {
"description": "No response body"
}
}
}
},
"/api/documents/{id}/thumb/": {
"get": {
"operationId": "documents_thumb_retrieve",
"description": "View the document thumbnail",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this document.",
"required": true
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string",
"format": "binary"
}
}
},
"description": ""
}
}
}
},
"/api/documents/bulk_download/": {
"post": {
"operationId": "documents_bulk_download_create",
"tags": [
"documents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkDownloadRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkDownload"
}
}
},
"description": ""
}
}
}
},
"/api/documents/bulk_edit/": {
"post": {
"operationId": "bulk_edit",
"description": "Perform a bulk edit operation on a list of documents",
"externalDocs": {
"description": "Further documentation",
"url": "https://docs.paperless-ngx.com/api/#bulk-editing"
},
"tags": [
"documents"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkEditRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkEditDocumentsResult"
}
}
},
"description": ""
}
}
}
},
"/api/documents/next_asn/": {
"get": {
"operationId": "documents_next_asn_retrieve",
"description": "Get the next available Archive Serial Number (ASN) for a new document",
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "integer"
}
}
},
"description": ""
}
}
}
},
"/api/documents/post_document/": {
"post": {
"operationId": "documents_post_document_create",
"description": "Upload a document via the API",
"externalDocs": {
"description": "Further documentation",
"url": "https://docs.paperless-ngx.com/api/#file-uploads"
},
"tags": [
"documents"
],
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PostDocumentRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
}
}
}
},
"/api/documents/selection_data/": {
"post": {
"operationId": "documents_selection_data_create",
"description": "Get selection data for the selected documents",
"tags": [
"documents"
],
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/DocumentListRequest"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentListRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SelectionData"
}
}
},
"description": ""
}
}
}
},
"/api/groups/": {
"get": {
"operationId": "groups_list",
"parameters": [
{
"in": "query",
"name": "name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__istartswith",
"schema": {
"type": "string"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"groups"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedGroupList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "groups_create",
"tags": [
"groups"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GroupRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/GroupRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/GroupRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Group"
}
}
},
"description": ""
}
}
}
},
"/api/groups/{id}/": {
"get": {
"operationId": "groups_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this group.",
"required": true
}
],
"tags": [
"groups"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Group"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "groups_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this group.",
"required": true
}
],
"tags": [
"groups"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GroupRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/GroupRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/GroupRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Group"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "groups_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this group.",
"required": true
}
],
"tags": [
"groups"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedGroupRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedGroupRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedGroupRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Group"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "groups_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this group.",
"required": true
}
],
"tags": [
"groups"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/logs/": {
"get": {
"operationId": "logs_list",
"description": "Logs view",
"tags": [
"logs"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"description": ""
}
}
}
},
"/api/logs/{id}/": {
"get": {
"operationId": "retrieve_log",
"description": "Single log view",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "string"
},
"required": true
}
],
"tags": [
"logs"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"description": ""
},
"404": {
"description": "No response body"
}
}
}
},
"/api/mail_accounts/": {
"get": {
"operationId": "mail_accounts_list",
"parameters": [
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"mail_accounts"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedMailAccountList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "mail_accounts_create",
"tags": [
"mail_accounts"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccount"
}
}
},
"description": ""
}
}
}
},
"/api/mail_accounts/{id}/": {
"get": {
"operationId": "mail_accounts_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail account.",
"required": true
}
],
"tags": [
"mail_accounts"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccount"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "mail_accounts_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail account.",
"required": true
}
],
"tags": [
"mail_accounts"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccount"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "mail_accounts_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail account.",
"required": true
}
],
"tags": [
"mail_accounts"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedMailAccountRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedMailAccountRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedMailAccountRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccount"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "mail_accounts_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail account.",
"required": true
}
],
"tags": [
"mail_accounts"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/mail_accounts/{id}/process/": {
"post": {
"operationId": "mail_account_process",
"description": "Manually process the selected mail account for new messages.",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail account.",
"required": true
}
],
"tags": [
"mail_accounts"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccountProcessResponse"
}
}
},
"description": ""
},
"404": {
"description": "No response body"
}
}
}
},
"/api/mail_accounts/test/": {
"post": {
"operationId": "mail_account_test",
"description": "Test a mail account",
"tags": [
"mail_accounts"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/MailAccountRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailAccountTestResponse"
}
}
},
"description": ""
},
"400": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
}
}
}
},
"/api/mail_rules/": {
"get": {
"operationId": "mail_rules_list",
"parameters": [
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"mail_rules"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedMailRuleList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "mail_rules_create",
"tags": [
"mail_rules"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailRuleRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/MailRuleRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/MailRuleRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailRule"
}
}
},
"description": ""
}
}
}
},
"/api/mail_rules/{id}/": {
"get": {
"operationId": "mail_rules_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail rule.",
"required": true
}
],
"tags": [
"mail_rules"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailRule"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "mail_rules_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail rule.",
"required": true
}
],
"tags": [
"mail_rules"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailRuleRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/MailRuleRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/MailRuleRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailRule"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "mail_rules_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail rule.",
"required": true
}
],
"tags": [
"mail_rules"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedMailRuleRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedMailRuleRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedMailRuleRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MailRule"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "mail_rules_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this mail rule.",
"required": true
}
],
"tags": [
"mail_rules"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/oauth/callback/": {
"get": {
"operationId": "oauth_callback_retrieve",
"description": "Callback view for OAuth2 authentication",
"tags": [
"oauth"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"description": "No response body"
}
}
}
},
"/api/profile/": {
"get": {
"operationId": "profile_retrieve",
"description": "User profile view, only available when logged in",
"tags": [
"profile"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Profile"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "profile_partial_update",
"description": "User profile view, only available when logged in",
"tags": [
"profile"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedProfileRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedProfileRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedProfileRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Profile"
}
}
},
"description": ""
}
}
}
},
"/api/profile/disconnect_social_account/": {
"post": {
"operationId": "profile_disconnect_social_account_create",
"description": "Disconnects a social account provider from the user account",
"tags": [
"profile"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer"
}
},
"required": [
"id"
]
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "integer"
}
}
},
"description": ""
},
"400": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
}
}
}
},
"/api/profile/generate_auth_token/": {
"post": {
"operationId": "profile_generate_auth_token_create",
"description": "Generates (or re-generates) an auth token, requires a logged in user\nunlike the default DRF endpoint",
"tags": [
"profile"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
}
}
}
},
"/api/profile/social_account_providers/": {
"get": {
"operationId": "profile_social_account_providers_retrieve",
"description": "List of social account providers",
"tags": [
"profile"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {}
}
}
},
"description": ""
}
}
}
},
"/api/profile/totp/": {
"get": {
"operationId": "profile_totp_retrieve",
"description": "Generates a new TOTP secret and returns the URL and SVG",
"tags": [
"profile"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {}
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "profile_totp_create",
"description": "Validates a TOTP code and activates the TOTP authenticator",
"tags": [
"profile"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secret": {
"type": "string"
},
"code": {
"type": "string"
}
},
"required": [
"secret",
"code"
]
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {}
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "profile_totp_destroy",
"description": "Deactivates the TOTP authenticator",
"tags": [
"profile"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
},
"description": ""
},
"404": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
}
}
}
},
"/api/remote_version/": {
"get": {
"operationId": "remote_version_retrieve",
"description": "Get the current version of the Paperless-NGX server",
"tags": [
"remote_version"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
},
{}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {}
}
}
},
"description": ""
}
}
}
},
"/api/saved_views/": {
"get": {
"operationId": "saved_views_list",
"parameters": [
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"saved_views"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedSavedViewList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "saved_views_create",
"tags": [
"saved_views"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SavedViewRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/SavedViewRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/SavedViewRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SavedView"
}
}
},
"description": ""
}
}
}
},
"/api/saved_views/{id}/": {
"get": {
"operationId": "saved_views_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this saved view.",
"required": true
}
],
"tags": [
"saved_views"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SavedView"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "saved_views_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this saved view.",
"required": true
}
],
"tags": [
"saved_views"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SavedViewRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/SavedViewRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/SavedViewRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SavedView"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "saved_views_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this saved view.",
"required": true
}
],
"tags": [
"saved_views"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedSavedViewRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedSavedViewRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedSavedViewRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SavedView"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "saved_views_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this saved view.",
"required": true
}
],
"tags": [
"saved_views"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/search/": {
"get": {
"operationId": "search_retrieve",
"description": "Global search",
"parameters": [
{
"in": "query",
"name": "db_only",
"schema": {
"type": "boolean"
},
"description": "Search only the database"
},
{
"in": "query",
"name": "query",
"schema": {
"type": "string"
},
"description": "Query to search for",
"required": true
}
],
"tags": [
"search"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SearchResult"
}
}
},
"description": ""
}
}
}
},
"/api/search/autocomplete/": {
"get": {
"operationId": "search_autocomplete_list",
"description": "Get a list of all available tags",
"parameters": [
{
"in": "query",
"name": "limit",
"schema": {
"type": "integer"
},
"description": "Number of completions to return"
},
{
"in": "query",
"name": "term",
"schema": {
"type": "string"
},
"description": "Term to search for"
}
],
"tags": [
"search"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"description": ""
}
}
}
},
"/api/share_links/": {
"get": {
"operationId": "share_links_list",
"parameters": [
{
"in": "query",
"name": "created__date__gt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__date__gte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__date__lt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__date__lte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "created__day",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "created__gt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "created__gte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "created__lt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "created__lte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "created__month",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "created__year",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "expiration__date__gt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "expiration__date__gte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "expiration__date__lt",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "expiration__date__lte",
"schema": {
"type": "string",
"format": "date"
}
},
{
"in": "query",
"name": "expiration__day",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "expiration__gt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "expiration__gte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "expiration__lt",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "expiration__lte",
"schema": {
"type": "string",
"format": "date-time"
}
},
{
"in": "query",
"name": "expiration__month",
"schema": {
"type": "number"
}
},
{
"in": "query",
"name": "expiration__year",
"schema": {
"type": "number"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"share_links"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedShareLinkList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "share_links_create",
"tags": [
"share_links"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShareLinkRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/ShareLinkRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/ShareLinkRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShareLink"
}
}
},
"description": ""
}
}
}
},
"/api/share_links/{id}/": {
"get": {
"operationId": "share_links_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this share link.",
"required": true
}
],
"tags": [
"share_links"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShareLink"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "share_links_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this share link.",
"required": true
}
],
"tags": [
"share_links"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShareLinkRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/ShareLinkRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/ShareLinkRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShareLink"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "share_links_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this share link.",
"required": true
}
],
"tags": [
"share_links"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedShareLinkRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedShareLinkRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedShareLinkRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShareLink"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "share_links_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this share link.",
"required": true
}
],
"tags": [
"share_links"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/statistics/": {
"get": {
"operationId": "statistics_retrieve",
"description": "Get statistics for the current user",
"tags": [
"statistics"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {}
}
}
},
"description": ""
}
}
}
},
"/api/status/": {
"get": {
"operationId": "status_retrieve",
"description": "Get the current system status of the Paperless-NGX server",
"tags": [
"status"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SystemStatus"
}
}
},
"description": ""
}
}
}
},
"/api/storage_paths/": {
"get": {
"operationId": "storage_paths_list",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__istartswith",
"schema": {
"type": "string"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "path__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "path__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "path__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "path__istartswith",
"schema": {
"type": "string"
}
}
],
"tags": [
"storage_paths"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedStoragePathList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "storage_paths_create",
"tags": [
"storage_paths"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePath"
}
}
},
"description": ""
}
}
}
},
"/api/storage_paths/{id}/": {
"get": {
"operationId": "storage_paths_retrieve",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this storage path.",
"required": true
}
],
"tags": [
"storage_paths"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePath"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "storage_paths_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this storage path.",
"required": true
}
],
"tags": [
"storage_paths"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePath"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "storage_paths_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this storage path.",
"required": true
}
],
"tags": [
"storage_paths"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedStoragePathRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedStoragePathRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedStoragePathRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePath"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "storage_paths_destroy",
"description": "When a storage path is deleted, see if documents\nusing it require a rename/move",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this storage path.",
"required": true
}
],
"tags": [
"storage_paths"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/storage_paths/test/": {
"post": {
"operationId": "storage_paths_test_create",
"description": "Test storage path against a document",
"tags": [
"storage_paths"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/StoragePathRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StoragePath"
}
}
},
"description": ""
}
}
}
},
"/api/tags/": {
"get": {
"operationId": "tags_list",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "query",
"name": "id",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "id__in",
"schema": {
"type": "array",
"items": {
"type": "integer"
}
},
"description": "Multiple values may be separated by commas.",
"explode": false,
"style": "form"
},
{
"in": "query",
"name": "name__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "name__istartswith",
"schema": {
"type": "string"
}
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"tags"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedTagList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "tags_create",
"tags": [
"tags"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TagRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/TagRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/TagRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Tag"
}
}
},
"description": ""
}
}
}
},
"/api/tags/{id}/": {
"get": {
"operationId": "tags_retrieve",
"parameters": [
{
"in": "query",
"name": "full_perms",
"schema": {
"type": "boolean"
}
},
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this tag.",
"required": true
}
],
"tags": [
"tags"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Tag"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "tags_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this tag.",
"required": true
}
],
"tags": [
"tags"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TagRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/TagRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/TagRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Tag"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "tags_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this tag.",
"required": true
}
],
"tags": [
"tags"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedTagRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedTagRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedTagRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Tag"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "tags_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this tag.",
"required": true
}
],
"tags": [
"tags"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/tasks/": {
"get": {
"operationId": "tasks_list",
"parameters": [
{
"in": "query",
"name": "acknowledged",
"schema": {
"type": "boolean"
},
"description": "Acknowledged"
},
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "status",
"schema": {
"type": "string",
"title": "Task State",
"enum": [
"FAILURE",
"PENDING",
"RECEIVED",
"RETRY",
"REVOKED",
"STARTED",
"SUCCESS"
]
},
"description": "Current state of the task being run\n\n* `FAILURE` - FAILURE\n* `PENDING` - PENDING\n* `RECEIVED` - RECEIVED\n* `RETRY` - RETRY\n* `REVOKED` - REVOKED\n* `STARTED` - STARTED\n* `SUCCESS` - SUCCESS"
},
{
"in": "query",
"name": "task_id",
"schema": {
"type": "string"
},
"description": "Filter tasks by Celery UUID"
},
{
"in": "query",
"name": "task_name",
"schema": {
"type": "string",
"nullable": true,
"enum": [
"check_sanity",
"consume_file",
"index_optimize",
"train_classifier"
]
},
"description": "Name of the task that was run\n\n* `consume_file` - Consume File\n* `train_classifier` - Train Classifier\n* `check_sanity` - Check Sanity\n* `index_optimize` - Index Optimize"
},
{
"in": "query",
"name": "type",
"schema": {
"type": "string",
"title": "Task Type",
"enum": [
"auto_task",
"manual_task",
"scheduled_task"
]
},
"description": "The type of task that was run\n\n* `auto_task` - Auto Task\n* `scheduled_task` - Scheduled Task\n* `manual_task` - Manual Task"
}
],
"tags": [
"tasks"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TasksView"
}
}
}
},
"description": ""
}
}
}
},
"/api/tasks/{id}/": {
"get": {
"operationId": "tasks_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this paperless task.",
"required": true
},
{
"in": "query",
"name": "task_id",
"schema": {
"type": "string"
},
"description": "Filter tasks by Celery UUID"
}
],
"tags": [
"tasks"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TasksView"
}
}
},
"description": ""
}
}
}
},
"/api/tasks/acknowledge/": {
"post": {
"operationId": "acknowledge_tasks",
"description": "Acknowledge a list of tasks",
"parameters": [
{
"in": "query",
"name": "task_id",
"schema": {
"type": "string"
},
"description": "Filter tasks by Celery UUID"
}
],
"tags": [
"tasks"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"tasks": {
"type": "array",
"items": {
"type": "integer"
}
}
},
"required": [
"tasks"
]
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AcknowledgeTasks"
}
}
},
"description": ""
},
"400": {
"description": "No response body"
}
}
}
},
"/api/tasks/run/": {
"post": {
"operationId": "tasks_run_create",
"parameters": [
{
"in": "query",
"name": "task_id",
"schema": {
"type": "string"
},
"description": "Filter tasks by Celery UUID"
}
],
"tags": [
"tasks"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TasksViewRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/TasksViewRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/TasksViewRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TasksView"
}
}
},
"description": ""
}
}
}
},
"/api/token/": {
"post": {
"operationId": "token_create",
"tags": [
"token"
],
"requestBody": {
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PaperlessAuthTokenRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PaperlessAuthTokenRequest"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaperlessAuthTokenRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaperlessAuthToken"
}
}
},
"description": ""
}
}
}
},
"/api/trash/": {
"get": {
"operationId": "trash_list",
"parameters": [
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"trash"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"description": "No response body"
}
}
},
"post": {
"operationId": "trash_create",
"tags": [
"trash"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TrashRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/TrashRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/TrashRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"description": "No response body"
}
}
}
},
"/api/ui_settings/": {
"get": {
"operationId": "ui_settings_retrieve",
"tags": [
"ui_settings"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UiSettingsView"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "ui_settings_create",
"tags": [
"ui_settings"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UiSettingsViewRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/UiSettingsViewRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/UiSettingsViewRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UiSettingsView"
}
}
},
"description": ""
}
}
}
},
"/api/users/": {
"get": {
"operationId": "users_list",
"parameters": [
{
"name": "ordering",
"required": false,
"in": "query",
"description": "Which field to use when ordering the results.",
"schema": {
"type": "string"
}
},
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
},
{
"in": "query",
"name": "username__icontains",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "username__iendswith",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "username__iexact",
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "username__istartswith",
"schema": {
"type": "string"
}
}
],
"tags": [
"users"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedUserList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "users_create",
"tags": [
"users"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/UserRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/UserRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
},
"description": ""
}
}
}
},
"/api/users/{id}/": {
"get": {
"operationId": "users_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this user.",
"required": true
}
],
"tags": [
"users"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "users_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this user.",
"required": true
}
],
"tags": [
"users"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/UserRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/UserRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "users_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this user.",
"required": true
}
],
"tags": [
"users"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedUserRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedUserRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedUserRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "users_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this user.",
"required": true
}
],
"tags": [
"users"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/users/{id}/deactivate_totp/": {
"post": {
"operationId": "users_deactivate_totp_create",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this user.",
"required": true
}
],
"tags": [
"users"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
},
"description": ""
},
"404": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
}
}
}
},
"/api/workflow_actions/": {
"get": {
"operationId": "workflow_actions_list",
"parameters": [
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"workflow_actions"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedWorkflowActionList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "workflow_actions_create",
"tags": [
"workflow_actions"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowAction"
}
}
},
"description": ""
}
}
}
},
"/api/workflow_actions/{id}/": {
"get": {
"operationId": "workflow_actions_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow action.",
"required": true
}
],
"tags": [
"workflow_actions"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowAction"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "workflow_actions_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow action.",
"required": true
}
],
"tags": [
"workflow_actions"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowAction"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "workflow_actions_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow action.",
"required": true
}
],
"tags": [
"workflow_actions"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowActionRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowActionRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowActionRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowAction"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "workflow_actions_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow action.",
"required": true
}
],
"tags": [
"workflow_actions"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/workflow_triggers/": {
"get": {
"operationId": "workflow_triggers_list",
"parameters": [
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"workflow_triggers"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedWorkflowTriggerList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "workflow_triggers_create",
"tags": [
"workflow_triggers"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowTrigger"
}
}
},
"description": ""
}
}
}
},
"/api/workflow_triggers/{id}/": {
"get": {
"operationId": "workflow_triggers_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow trigger.",
"required": true
}
],
"tags": [
"workflow_triggers"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowTrigger"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "workflow_triggers_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow trigger.",
"required": true
}
],
"tags": [
"workflow_triggers"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowTrigger"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "workflow_triggers_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow trigger.",
"required": true
}
],
"tags": [
"workflow_triggers"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowTriggerRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowTriggerRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowTriggerRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowTrigger"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "workflow_triggers_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow trigger.",
"required": true
}
],
"tags": [
"workflow_triggers"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
},
"/api/workflows/": {
"get": {
"operationId": "workflows_list",
"parameters": [
{
"name": "page",
"required": false,
"in": "query",
"description": "A page number within the paginated result set.",
"schema": {
"type": "integer"
}
},
{
"name": "page_size",
"required": false,
"in": "query",
"description": "Number of results to return per page.",
"schema": {
"type": "integer"
}
}
],
"tags": [
"workflows"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedWorkflowList"
}
}
},
"description": ""
}
}
},
"post": {
"operationId": "workflows_create",
"tags": [
"workflows"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/WorkflowRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/WorkflowRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Workflow"
}
}
},
"description": ""
}
}
}
},
"/api/workflows/{id}/": {
"get": {
"operationId": "workflows_retrieve",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow.",
"required": true
}
],
"tags": [
"workflows"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Workflow"
}
}
},
"description": ""
}
}
},
"put": {
"operationId": "workflows_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow.",
"required": true
}
],
"tags": [
"workflows"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WorkflowRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/WorkflowRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/WorkflowRequest"
}
}
},
"required": true
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Workflow"
}
}
},
"description": ""
}
}
},
"patch": {
"operationId": "workflows_partial_update",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow.",
"required": true
}
],
"tags": [
"workflows"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowRequest"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/PatchedWorkflowRequest"
}
}
}
},
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Workflow"
}
}
},
"description": ""
}
}
},
"delete": {
"operationId": "workflows_destroy",
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "integer"
},
"description": "A unique integer value identifying this workflow.",
"required": true
}
],
"tags": [
"workflows"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"204": {
"description": "No response body"
}
}
}
}
},
"components": {
"schemas": {
"AccountTypeEnum": {
"enum": [
1,
2,
3
],
"type": "integer",
"description": "* `1` - IMAP\n* `2` - Gmail OAuth\n* `3` - Outlook OAuth"
},
"AcknowledgeTasks": {
"type": "object",
"properties": {
"result": {
"type": "integer"
}
},
"required": [
"result"
]
},
"Actor": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"username": {
"type": "string"
}
},
"required": [
"id",
"username"
]
},
"ApplicationConfiguration": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"user_args": {
"nullable": true
},
"barcode_tag_mapping": {
"nullable": true
},
"output_type": {
"nullable": true,
"title": "Sets the output PDF type",
"oneOf": [
{
"$ref": "#/components/schemas/OutputTypeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"pages": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Do OCR from page 1 to this value"
},
"language": {
"type": "string",
"nullable": true,
"title": "Do OCR using these languages",
"maxLength": 32
},
"mode": {
"nullable": true,
"title": "Sets the OCR mode",
"oneOf": [
{
"$ref": "#/components/schemas/ModeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"skip_archive_file": {
"nullable": true,
"title": "Controls the generation of an archive file",
"oneOf": [
{
"$ref": "#/components/schemas/SkipArchiveFileEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"image_dpi": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets image DPI fallback value"
},
"unpaper_clean": {
"nullable": true,
"title": "Controls the unpaper cleaning",
"oneOf": [
{
"$ref": "#/components/schemas/UnpaperCleanEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"deskew": {
"type": "boolean",
"nullable": true,
"title": "Enables deskew"
},
"rotate_pages": {
"type": "boolean",
"nullable": true,
"title": "Enables page rotation"
},
"rotate_pages_threshold": {
"type": "number",
"format": "double",
"minimum": 0.0,
"nullable": true,
"title": "Sets the threshold for rotation of pages"
},
"max_image_pixels": {
"type": "number",
"format": "double",
"minimum": 0.0,
"nullable": true,
"title": "Sets the maximum image size for decompression"
},
"color_conversion_strategy": {
"nullable": true,
"title": "Sets the Ghostscript color conversion strategy",
"oneOf": [
{
"$ref": "#/components/schemas/ColorConversionStrategyEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"app_title": {
"type": "string",
"nullable": true,
"title": "Application title",
"maxLength": 48
},
"app_logo": {
"type": "string",
"format": "uri",
"nullable": true,
"title": "Application logo",
"pattern": "(?:jpg|png|gif|svg)$"
},
"barcodes_enabled": {
"type": "boolean",
"nullable": true,
"title": "Enables barcode scanning"
},
"barcode_enable_tiff_support": {
"type": "boolean",
"nullable": true,
"title": "Enables barcode TIFF support"
},
"barcode_string": {
"type": "string",
"nullable": true,
"title": "Sets the barcode string",
"maxLength": 32
},
"barcode_retain_split_pages": {
"type": "boolean",
"nullable": true,
"title": "Retains split pages"
},
"barcode_enable_asn": {
"type": "boolean",
"nullable": true,
"title": "Enables ASN barcode"
},
"barcode_asn_prefix": {
"type": "string",
"nullable": true,
"title": "Sets the ASN barcode prefix",
"maxLength": 32
},
"barcode_upscale": {
"type": "number",
"format": "double",
"minimum": 1.0,
"nullable": true,
"title": "Sets the barcode upscale factor"
},
"barcode_dpi": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets the barcode DPI"
},
"barcode_max_pages": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets the maximum pages for barcode"
},
"barcode_enable_tag": {
"type": "boolean",
"nullable": true,
"title": "Enables tag barcode"
}
},
"required": [
"barcode_tag_mapping",
"id",
"user_args"
]
},
"ApplicationConfigurationRequest": {
"type": "object",
"properties": {
"user_args": {
"nullable": true
},
"barcode_tag_mapping": {
"nullable": true
},
"output_type": {
"nullable": true,
"title": "Sets the output PDF type",
"oneOf": [
{
"$ref": "#/components/schemas/OutputTypeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"pages": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Do OCR from page 1 to this value"
},
"language": {
"type": "string",
"nullable": true,
"title": "Do OCR using these languages",
"maxLength": 32
},
"mode": {
"nullable": true,
"title": "Sets the OCR mode",
"oneOf": [
{
"$ref": "#/components/schemas/ModeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"skip_archive_file": {
"nullable": true,
"title": "Controls the generation of an archive file",
"oneOf": [
{
"$ref": "#/components/schemas/SkipArchiveFileEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"image_dpi": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets image DPI fallback value"
},
"unpaper_clean": {
"nullable": true,
"title": "Controls the unpaper cleaning",
"oneOf": [
{
"$ref": "#/components/schemas/UnpaperCleanEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"deskew": {
"type": "boolean",
"nullable": true,
"title": "Enables deskew"
},
"rotate_pages": {
"type": "boolean",
"nullable": true,
"title": "Enables page rotation"
},
"rotate_pages_threshold": {
"type": "number",
"format": "double",
"minimum": 0.0,
"nullable": true,
"title": "Sets the threshold for rotation of pages"
},
"max_image_pixels": {
"type": "number",
"format": "double",
"minimum": 0.0,
"nullable": true,
"title": "Sets the maximum image size for decompression"
},
"color_conversion_strategy": {
"nullable": true,
"title": "Sets the Ghostscript color conversion strategy",
"oneOf": [
{
"$ref": "#/components/schemas/ColorConversionStrategyEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"app_title": {
"type": "string",
"nullable": true,
"title": "Application title",
"maxLength": 48
},
"app_logo": {
"type": "string",
"format": "binary",
"nullable": true,
"title": "Application logo",
"pattern": "(?:jpg|png|gif|svg)$"
},
"barcodes_enabled": {
"type": "boolean",
"nullable": true,
"title": "Enables barcode scanning"
},
"barcode_enable_tiff_support": {
"type": "boolean",
"nullable": true,
"title": "Enables barcode TIFF support"
},
"barcode_string": {
"type": "string",
"nullable": true,
"title": "Sets the barcode string",
"maxLength": 32
},
"barcode_retain_split_pages": {
"type": "boolean",
"nullable": true,
"title": "Retains split pages"
},
"barcode_enable_asn": {
"type": "boolean",
"nullable": true,
"title": "Enables ASN barcode"
},
"barcode_asn_prefix": {
"type": "string",
"nullable": true,
"title": "Sets the ASN barcode prefix",
"maxLength": 32
},
"barcode_upscale": {
"type": "number",
"format": "double",
"minimum": 1.0,
"nullable": true,
"title": "Sets the barcode upscale factor"
},
"barcode_dpi": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets the barcode DPI"
},
"barcode_max_pages": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets the maximum pages for barcode"
},
"barcode_enable_tag": {
"type": "boolean",
"nullable": true,
"title": "Enables tag barcode"
}
},
"required": [
"barcode_tag_mapping",
"user_args"
]
},
"AssignCorrespondentFromEnum": {
"enum": [
1,
2,
3,
4
],
"type": "integer",
"description": "* `1` - Do not assign a correspondent\n* `2` - Use mail address\n* `3` - Use name (or mail address if not available)\n* `4` - Use correspondent selected below"
},
"AssignTitleFromEnum": {
"enum": [
1,
2,
3
],
"type": "integer",
"description": "* `1` - Use subject as title\n* `2` - Use attachment filename as title\n* `3` - Do not assign title from rule"
},
"AttachmentTypeEnum": {
"enum": [
1,
2
],
"type": "integer",
"description": "* `1` - Only process attachments.\n* `2` - Process all files, including 'inline' attachments."
},
"BasicUser": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"username": {
"type": "string",
"description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
"pattern": "^[\\w.@+-]+$",
"maxLength": 150
},
"first_name": {
"type": "string",
"maxLength": 150
},
"last_name": {
"type": "string",
"maxLength": 150
}
},
"required": [
"id",
"username"
]
},
"BasicUserRequest": {
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 1,
"description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
"pattern": "^[\\w.@+-]+$",
"maxLength": 150
},
"first_name": {
"type": "string",
"maxLength": 150
},
"last_name": {
"type": "string",
"maxLength": 150
}
},
"required": [
"username"
]
},
"BlankEnum": {
"enum": [
""
]
},
"BulkDownload": {
"type": "object",
"properties": {
"content": {
"allOf": [
{
"$ref": "#/components/schemas/ContentEnum"
}
],
"default": "archive"
},
"compression": {
"allOf": [
{
"$ref": "#/components/schemas/CompressionEnum"
}
],
"default": "none"
},
"follow_formatting": {
"type": "boolean",
"default": false
}
}
},
"BulkDownloadRequest": {
"type": "object",
"properties": {
"documents": {
"type": "array",
"items": {
"type": "integer"
},
"writeOnly": true
},
"content": {
"allOf": [
{
"$ref": "#/components/schemas/ContentEnum"
}
],
"default": "archive"
},
"compression": {
"allOf": [
{
"$ref": "#/components/schemas/CompressionEnum"
}
],
"default": "none"
},
"follow_formatting": {
"type": "boolean",
"default": false
}
},
"required": [
"documents"
]
},
"BulkEditDocumentsResult": {
"type": "object",
"properties": {
"result": {
"type": "string"
}
},
"required": [
"result"
]
},
"BulkEditObjectsRequest": {
"type": "object",
"properties": {
"objects": {
"type": "array",
"items": {
"type": "integer"
},
"writeOnly": true
},
"object_type": {
"allOf": [
{
"$ref": "#/components/schemas/ObjectTypeEnum"
}
],
"writeOnly": true
},
"operation": {
"allOf": [
{
"$ref": "#/components/schemas/OperationEnum"
}
],
"writeOnly": true
},
"owner": {
"type": "integer",
"nullable": true
},
"permissions": {
"type": "object",
"additionalProperties": {},
"writeOnly": true,
"title": "Set permissions"
},
"merge": {
"type": "boolean",
"writeOnly": true,
"default": false
}
},
"required": [
"object_type",
"objects",
"operation"
]
},
"BulkEditRequest": {
"type": "object",
"properties": {
"documents": {
"type": "array",
"items": {
"type": "integer"
},
"writeOnly": true
},
"method": {
"allOf": [
{
"$ref": "#/components/schemas/MethodEnum"
}
],
"writeOnly": true
},
"parameters": {
"type": "object",
"additionalProperties": {},
"writeOnly": true,
"default": {}
}
},
"required": [
"documents",
"method"
]
},
"BulkEditResult": {
"type": "object",
"properties": {
"result": {
"type": "string"
}
},
"required": [
"result"
]
},
"Classifier": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"error": {
"type": "string"
},
"last_trained": {
"type": "string",
"format": "date-time"
}
},
"required": [
"error",
"last_trained",
"status"
]
},
"ColorConversionStrategyEnum": {
"enum": [
"LeaveColorUnchanged",
"RGB",
"UseDeviceIndependentColor",
"Gray",
"CMYK"
],
"type": "string",
"description": "* `LeaveColorUnchanged` - LeaveColorUnchanged\n* `RGB` - RGB\n* `UseDeviceIndependentColor` - UseDeviceIndependentColor\n* `Gray` - Gray\n* `CMYK` - CMYK"
},
"CompressionEnum": {
"enum": [
"none",
"deflated",
"bzip2",
"lzma"
],
"type": "string",
"description": "* `none` - none\n* `deflated` - deflated\n* `bzip2` - bzip2\n* `lzma` - lzma"
},
"ConsumptionScopeEnum": {
"enum": [
1,
2,
3
],
"type": "integer",
"description": "* `1` - Only process attachments.\n* `2` - Process full Mail (with embedded attachments in file) as .eml\n* `3` - Process full Mail (with embedded attachments in file) as .eml + process attachments as separate documents"
},
"ContentEnum": {
"enum": [
"archive",
"originals",
"both"
],
"type": "string",
"description": "* `archive` - archive\n* `originals` - originals\n* `both` - both"
},
"Correspondent": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"slug": {
"type": "string",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 128
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"document_count": {
"type": "integer",
"readOnly": true
},
"last_correspondence": {
"type": "string",
"format": "date",
"readOnly": true
},
"owner": {
"type": "integer",
"nullable": true
},
"permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"readOnly": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"document_count",
"id",
"last_correspondence",
"name",
"permissions",
"slug",
"user_can_change"
]
},
"CorrespondentCounts": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"document_count": {
"type": "integer"
}
},
"required": [
"document_count",
"id"
]
},
"CorrespondentRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
},
"required": [
"name"
]
},
"CustomField": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 128
},
"data_type": {
"$ref": "#/components/schemas/DataTypeEnum"
},
"extra_data": {
"nullable": true,
"description": "Extra data for the custom field, such as select options"
},
"document_count": {
"type": "integer",
"readOnly": true
}
},
"required": [
"data_type",
"document_count",
"id",
"name"
]
},
"CustomFieldCounts": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"document_count": {
"type": "integer"
}
},
"required": [
"document_count",
"id"
]
},
"CustomFieldInstance": {
"type": "object",
"properties": {
"value": {
"oneOf": [
{
"type": "string"
},
{
"type": "integer"
},
{
"type": "number",
"format": "double"
},
{
"type": "object",
"additionalProperties": {}
}
],
"nullable": true,
"description": "Given the *incoming* primitive data, return the value for this field\nthat should be validated and transformed to a native value."
},
"field": {
"type": "integer"
}
},
"required": [
"field",
"value"
]
},
"CustomFieldInstanceRequest": {
"type": "object",
"properties": {
"value": {
"oneOf": [
{
"type": "string"
},
{
"type": "integer"
},
{
"type": "number",
"format": "double"
},
{
"type": "object",
"additionalProperties": {}
}
],
"nullable": true,
"description": "Given the *incoming* primitive data, return the value for this field\nthat should be validated and transformed to a native value."
},
"field": {
"type": "integer"
}
},
"required": [
"field",
"value"
]
},
"CustomFieldRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"data_type": {
"$ref": "#/components/schemas/DataTypeEnum"
},
"extra_data": {
"nullable": true,
"description": "Extra data for the custom field, such as select options"
}
},
"required": [
"data_type",
"name"
]
},
"DataTypeEnum": {
"enum": [
"string",
"url",
"date",
"boolean",
"integer",
"float",
"monetary",
"documentlink",
"select"
],
"type": "string",
"description": "* `string` - string\n* `url` - url\n* `date` - date\n* `boolean` - boolean\n* `integer` - integer\n* `float` - float\n* `monetary` - monetary\n* `documentlink` - documentlink\n* `select` - select"
},
"Database": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"url": {
"type": "string"
},
"status": {
"type": "string"
},
"error": {
"type": "string"
},
"migration_status": {
"$ref": "#/components/schemas/MigrationStatus"
}
},
"required": [
"error",
"migration_status",
"status",
"type",
"url"
]
},
"DisplayModeEnum": {
"enum": [
"table",
"smallCards",
"largeCards"
],
"type": "string",
"description": "* `table` - Table\n* `smallCards` - Small Cards\n* `largeCards` - Large Cards"
},
"Document": {
"type": "object",
"description": "Adds update nested feature",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"correspondent": {
"type": "integer",
"nullable": true
},
"document_type": {
"type": "integer",
"nullable": true
},
"storage_path": {
"type": "integer",
"nullable": true
},
"title": {
"type": "string",
"maxLength": 128
},
"content": {
"type": "string",
"description": "The raw, text-only data of the document. This field is primarily used for searching."
},
"tags": {
"type": "array",
"items": {
"type": "integer"
}
},
"created": {
"type": "string",
"format": "date"
},
"created_date": {
"type": "string",
"format": "date",
"deprecated": true
},
"modified": {
"type": "string",
"format": "date-time",
"readOnly": true
},
"added": {
"type": "string",
"format": "date-time",
"readOnly": true
},
"deleted_at": {
"type": "string",
"format": "date-time",
"nullable": true
},
"archive_serial_number": {
"type": "integer",
"maximum": 4294967295,
"minimum": 0,
"format": "int64",
"nullable": true,
"description": "The position of this document in your physical document archive."
},
"original_file_name": {
"type": "string",
"nullable": true,
"readOnly": true
},
"archived_file_name": {
"type": "string",
"nullable": true,
"readOnly": true
},
"owner": {
"type": "integer",
"nullable": true
},
"permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"readOnly": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
},
"is_shared_by_requester": {
"type": "boolean",
"readOnly": true
},
"notes": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Notes"
},
"readOnly": true
},
"custom_fields": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CustomFieldInstance"
}
},
"page_count": {
"type": "integer",
"nullable": true,
"readOnly": true
},
"mime_type": {
"type": "string",
"readOnly": true
}
},
"required": [
"added",
"archived_file_name",
"correspondent",
"document_type",
"id",
"is_shared_by_requester",
"mime_type",
"modified",
"notes",
"original_file_name",
"page_count",
"permissions",
"storage_path",
"tags",
"user_can_change"
]
},
"DocumentListRequest": {
"type": "object",
"properties": {
"documents": {
"type": "array",
"items": {
"type": "integer"
},
"writeOnly": true
}
},
"required": [
"documents"
]
},
"DocumentRequest": {
"type": "object",
"description": "Adds update nested feature",
"properties": {
"correspondent": {
"type": "integer",
"nullable": true
},
"document_type": {
"type": "integer",
"nullable": true
},
"storage_path": {
"type": "integer",
"nullable": true
},
"title": {
"type": "string",
"maxLength": 128
},
"content": {
"type": "string",
"description": "The raw, text-only data of the document. This field is primarily used for searching."
},
"tags": {
"type": "array",
"items": {
"type": "integer"
}
},
"created": {
"type": "string",
"format": "date"
},
"created_date": {
"type": "string",
"format": "date",
"deprecated": true
},
"deleted_at": {
"type": "string",
"format": "date-time",
"nullable": true
},
"archive_serial_number": {
"type": "integer",
"maximum": 4294967295,
"minimum": 0,
"format": "int64",
"nullable": true,
"description": "The position of this document in your physical document archive."
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
},
"custom_fields": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CustomFieldInstanceRequest"
}
},
"remove_inbox_tags": {
"type": "boolean",
"writeOnly": true,
"nullable": true,
"default": false
}
},
"required": [
"correspondent",
"document_type",
"storage_path",
"tags"
]
},
"DocumentType": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"slug": {
"type": "string",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 128
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"document_count": {
"type": "integer",
"readOnly": true
},
"owner": {
"type": "integer",
"nullable": true
},
"permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"readOnly": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"document_count",
"id",
"name",
"permissions",
"slug",
"user_can_change"
]
},
"DocumentTypeCounts": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"document_count": {
"type": "integer"
}
},
"required": [
"document_count",
"id"
]
},
"DocumentTypeRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
},
"required": [
"name"
]
},
"EmailRequestRequest": {
"type": "object",
"properties": {
"addresses": {
"type": "string",
"minLength": 1
},
"subject": {
"type": "string",
"minLength": 1
},
"message": {
"type": "string",
"minLength": 1
},
"use_archive_version": {
"type": "boolean",
"default": true
}
},
"required": [
"addresses",
"message",
"subject"
]
},
"EmailResponse": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
]
},
"FileVersionEnum": {
"enum": [
"archive",
"original"
],
"type": "string",
"description": "* `archive` - Archive\n* `original` - Original"
},
"Group": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 150
},
"permissions": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"id",
"name",
"permissions"
]
},
"GroupRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 150
},
"permissions": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
},
"required": [
"name",
"permissions"
]
},
"ImapSecurityEnum": {
"enum": [
1,
2,
3
],
"type": "integer",
"description": "* `1` - No encryption\n* `2` - Use SSL\n* `3` - Use STARTTLS"
},
"Index": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"error": {
"type": "string"
},
"last_modified": {
"type": "string",
"format": "date-time"
}
},
"required": [
"error",
"last_modified",
"status"
]
},
"LogEntry": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"timestamp": {
"type": "string",
"format": "date-time"
},
"action": {
"type": "string"
},
"changes": {
"type": "object",
"additionalProperties": {}
},
"actor": {
"$ref": "#/components/schemas/Actor"
}
},
"required": [
"action",
"actor",
"changes",
"id",
"timestamp"
]
},
"MailAccount": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 256
},
"imap_server": {
"type": "string",
"maxLength": 256
},
"imap_port": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": -9223372036854775808,
"format": "int64",
"nullable": true,
"description": "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections."
},
"imap_security": {
"allOf": [
{
"$ref": "#/components/schemas/ImapSecurityEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"username": {
"type": "string",
"maxLength": 256
},
"password": {
"type": "string"
},
"character_set": {
"type": "string",
"description": "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'.",
"maxLength": 256
},
"is_token": {
"type": "boolean",
"title": "Is token authentication"
},
"owner": {
"type": "integer",
"nullable": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
},
"account_type": {
"allOf": [
{
"$ref": "#/components/schemas/AccountTypeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"expiration": {
"type": "string",
"format": "date-time",
"nullable": true,
"description": "The expiration date of the refresh token. "
}
},
"required": [
"id",
"imap_server",
"name",
"password",
"user_can_change",
"username"
]
},
"MailAccountProcessResponse": {
"type": "object",
"properties": {
"result": {
"type": "string",
"default": "OK"
}
}
},
"MailAccountRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"imap_server": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"imap_port": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": -9223372036854775808,
"format": "int64",
"nullable": true,
"description": "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections."
},
"imap_security": {
"allOf": [
{
"$ref": "#/components/schemas/ImapSecurityEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"username": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"password": {
"type": "string",
"minLength": 1
},
"character_set": {
"type": "string",
"minLength": 1,
"description": "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'.",
"maxLength": 256
},
"is_token": {
"type": "boolean",
"title": "Is token authentication"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
},
"account_type": {
"allOf": [
{
"$ref": "#/components/schemas/AccountTypeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"expiration": {
"type": "string",
"format": "date-time",
"nullable": true,
"description": "The expiration date of the refresh token. "
}
},
"required": [
"imap_server",
"name",
"password",
"username"
]
},
"MailAccountTestResponse": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
}
},
"required": [
"success"
]
},
"MailRule": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 256
},
"account": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"folder": {
"type": "string",
"description": "Subfolders must be separated by a delimiter, often a dot ('.') or slash ('/'), but it varies by mail server.",
"maxLength": 256
},
"filter_from": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_to": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_subject": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_body": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_attachment_filename_include": {
"type": "string",
"nullable": true,
"title": "Filter attachment filename inclusive",
"description": "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"filter_attachment_filename_exclude": {
"type": "string",
"nullable": true,
"title": "Filter attachment filename exclusive",
"description": "Do not consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"maximum_age": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 0,
"format": "int64",
"description": "Specified in days."
},
"action": {
"allOf": [
{
"$ref": "#/components/schemas/MailRuleActionEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"action_parameter": {
"type": "string",
"nullable": true,
"default": ""
},
"assign_title_from": {
"allOf": [
{
"$ref": "#/components/schemas/AssignTitleFromEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_tags": {
"type": "array",
"items": {
"type": "integer",
"nullable": true
}
},
"assign_correspondent_from": {
"allOf": [
{
"$ref": "#/components/schemas/AssignCorrespondentFromEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_correspondent": {
"type": "integer",
"nullable": true
},
"assign_document_type": {
"type": "integer",
"nullable": true
},
"assign_owner_from_rule": {
"type": "boolean",
"title": "Assign the rule owner to documents"
},
"order": {
"type": "integer"
},
"attachment_type": {
"allOf": [
{
"$ref": "#/components/schemas/AttachmentTypeEnum"
}
],
"description": "Inline attachments include embedded images, so it's best to combine this option with a filename filter.\n\n* `1` - Only process attachments.\n* `2` - Process all files, including 'inline' attachments.",
"minimum": 0,
"maximum": 9223372036854775807
},
"consumption_scope": {
"allOf": [
{
"$ref": "#/components/schemas/ConsumptionScopeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"pdf_layout": {
"allOf": [
{
"$ref": "#/components/schemas/PdfLayoutEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"owner": {
"type": "integer",
"nullable": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"account",
"id",
"name",
"user_can_change"
]
},
"MailRuleActionEnum": {
"enum": [
1,
2,
3,
4,
5
],
"type": "integer",
"description": "* `1` - Delete\n* `2` - Move to specified folder\n* `3` - Mark as read, don't process read mails\n* `4` - Flag the mail, don't process flagged mails\n* `5` - Tag the mail with specified tag, don't process tagged mails"
},
"MailRuleRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"account": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"folder": {
"type": "string",
"minLength": 1,
"description": "Subfolders must be separated by a delimiter, often a dot ('.') or slash ('/'), but it varies by mail server.",
"maxLength": 256
},
"filter_from": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_to": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_subject": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_body": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_attachment_filename_include": {
"type": "string",
"nullable": true,
"title": "Filter attachment filename inclusive",
"description": "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"filter_attachment_filename_exclude": {
"type": "string",
"nullable": true,
"title": "Filter attachment filename exclusive",
"description": "Do not consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"maximum_age": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 0,
"format": "int64",
"description": "Specified in days."
},
"action": {
"allOf": [
{
"$ref": "#/components/schemas/MailRuleActionEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"action_parameter": {
"type": "string",
"nullable": true,
"minLength": 1,
"default": ""
},
"assign_title_from": {
"allOf": [
{
"$ref": "#/components/schemas/AssignTitleFromEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_tags": {
"type": "array",
"items": {
"type": "integer",
"nullable": true
}
},
"assign_correspondent_from": {
"allOf": [
{
"$ref": "#/components/schemas/AssignCorrespondentFromEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_correspondent": {
"type": "integer",
"nullable": true
},
"assign_document_type": {
"type": "integer",
"nullable": true
},
"assign_owner_from_rule": {
"type": "boolean",
"title": "Assign the rule owner to documents"
},
"order": {
"type": "integer"
},
"attachment_type": {
"allOf": [
{
"$ref": "#/components/schemas/AttachmentTypeEnum"
}
],
"description": "Inline attachments include embedded images, so it's best to combine this option with a filename filter.\n\n* `1` - Only process attachments.\n* `2` - Process all files, including 'inline' attachments.",
"minimum": 0,
"maximum": 9223372036854775807
},
"consumption_scope": {
"allOf": [
{
"$ref": "#/components/schemas/ConsumptionScopeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"pdf_layout": {
"allOf": [
{
"$ref": "#/components/schemas/PdfLayoutEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
},
"required": [
"account",
"name"
]
},
"MatchingAlgorithm": {
"enum": [
0,
1,
2,
3,
4,
5,
6
],
"type": "integer",
"description": "* `0` - None\n* `1` - Any word\n* `2` - All words\n* `3` - Exact match\n* `4` - Regular expression\n* `5` - Fuzzy word\n* `6` - Automatic"
},
"Metadata": {
"type": "object",
"properties": {
"original_checksum": {
"type": "string"
},
"original_size": {
"type": "integer"
},
"original_mime_type": {
"type": "string"
},
"media_filename": {
"type": "string"
},
"has_archive_version": {
"type": "boolean"
},
"original_metadata": {
"type": "object",
"additionalProperties": {}
},
"archive_checksum": {
"type": "string"
},
"archive_media_filename": {
"type": "string"
},
"original_filename": {
"type": "string"
},
"archive_size": {
"type": "integer"
},
"archive_metadata": {
"type": "object",
"additionalProperties": {}
},
"lang": {
"type": "string"
}
},
"required": [
"archive_checksum",
"archive_media_filename",
"archive_metadata",
"archive_size",
"has_archive_version",
"lang",
"media_filename",
"original_checksum",
"original_filename",
"original_metadata",
"original_mime_type",
"original_size"
]
},
"MethodEnum": {
"enum": [
"set_correspondent",
"set_document_type",
"set_storage_path",
"add_tag",
"remove_tag",
"modify_tags",
"modify_custom_fields",
"delete",
"reprocess",
"set_permissions",
"rotate",
"merge",
"split",
"delete_pages",
"edit_pdf"
],
"type": "string",
"description": "* `set_correspondent` - set_correspondent\n* `set_document_type` - set_document_type\n* `set_storage_path` - set_storage_path\n* `add_tag` - add_tag\n* `remove_tag` - remove_tag\n* `modify_tags` - modify_tags\n* `modify_custom_fields` - modify_custom_fields\n* `delete` - delete\n* `reprocess` - reprocess\n* `set_permissions` - set_permissions\n* `rotate` - rotate\n* `merge` - merge\n* `split` - split\n* `delete_pages` - delete_pages\n* `edit_pdf` - edit_pdf"
},
"MigrationStatus": {
"type": "object",
"properties": {
"latest_migration": {
"type": "string"
},
"unapplied_migrations": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"latest_migration",
"unapplied_migrations"
]
},
"ModeEnum": {
"enum": [
"skip",
"redo",
"force",
"skip_noarchive"
],
"type": "string",
"description": "* `skip` - skip\n* `redo` - redo\n* `force` - force\n* `skip_noarchive` - skip_noarchive"
},
"NoteCreateRequestRequest": {
"type": "object",
"properties": {
"note": {
"type": "string",
"minLength": 1
}
},
"required": [
"note"
]
},
"Notes": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"note": {
"type": "string",
"title": "Content",
"description": "Note for the document"
},
"created": {
"type": "string",
"format": "date-time"
},
"user": {
"allOf": [
{
"$ref": "#/components/schemas/BasicUser"
}
],
"readOnly": true
}
},
"required": [
"id",
"user"
]
},
"NotesRequest": {
"type": "object",
"properties": {
"note": {
"type": "string",
"title": "Content",
"description": "Note for the document"
},
"created": {
"type": "string",
"format": "date-time"
}
}
},
"NullEnum": {
"enum": [
null
]
},
"ObjectTypeEnum": {
"enum": [
"tags",
"correspondents",
"document_types",
"storage_paths"
],
"type": "string",
"description": "* `tags` - tags\n* `correspondents` - correspondents\n* `document_types` - document_types\n* `storage_paths` - storage_paths"
},
"OperationEnum": {
"enum": [
"set_permissions",
"delete"
],
"type": "string",
"description": "* `set_permissions` - set_permissions\n* `delete` - delete"
},
"OutputTypeEnum": {
"enum": [
"pdf",
"pdfa",
"pdfa-1",
"pdfa-2",
"pdfa-3"
],
"type": "string",
"description": "* `pdf` - pdf\n* `pdfa` - pdfa\n* `pdfa-1` - pdfa-1\n* `pdfa-2` - pdfa-2\n* `pdfa-3` - pdfa-3"
},
"PaginatedCorrespondentList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Correspondent"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedCustomFieldList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CustomField"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedDocumentList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Document"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedDocumentTypeList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/DocumentType"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedGroupList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Group"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedLogEntryList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LogEntry"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedMailAccountList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MailAccount"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedMailRuleList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MailRule"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedNotesList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Notes"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedSavedViewList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SavedView"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedShareLinkList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ShareLink"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedStoragePathList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/StoragePath"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedTagList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Tag"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedUserList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/User"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedWorkflowActionList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowAction"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedWorkflowList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Workflow"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaginatedWorkflowTriggerList": {
"type": "object",
"required": [
"count",
"results"
],
"properties": {
"count": {
"type": "integer",
"example": 123
},
"next": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=4"
},
"previous": {
"type": "string",
"nullable": true,
"format": "uri",
"example": "http://api.example.org/accounts/?page=2"
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowTrigger"
}
},
"all": {
"type": "array",
"example": "[1, 2, 3]"
}
}
},
"PaperlessAuthToken": {
"type": "object",
"properties": {
"token": {
"type": "string",
"readOnly": true
}
},
"required": [
"token"
]
},
"PaperlessAuthTokenRequest": {
"type": "object",
"properties": {
"username": {
"type": "string",
"writeOnly": true,
"minLength": 1
},
"password": {
"type": "string",
"writeOnly": true,
"minLength": 1
},
"code": {
"type": "string",
"writeOnly": true,
"minLength": 1,
"title": "MFA Code"
}
},
"required": [
"password",
"username"
]
},
"PatchedApplicationConfigurationRequest": {
"type": "object",
"properties": {
"user_args": {
"nullable": true
},
"barcode_tag_mapping": {
"nullable": true
},
"output_type": {
"nullable": true,
"title": "Sets the output PDF type",
"oneOf": [
{
"$ref": "#/components/schemas/OutputTypeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"pages": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Do OCR from page 1 to this value"
},
"language": {
"type": "string",
"nullable": true,
"title": "Do OCR using these languages",
"maxLength": 32
},
"mode": {
"nullable": true,
"title": "Sets the OCR mode",
"oneOf": [
{
"$ref": "#/components/schemas/ModeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"skip_archive_file": {
"nullable": true,
"title": "Controls the generation of an archive file",
"oneOf": [
{
"$ref": "#/components/schemas/SkipArchiveFileEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"image_dpi": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets image DPI fallback value"
},
"unpaper_clean": {
"nullable": true,
"title": "Controls the unpaper cleaning",
"oneOf": [
{
"$ref": "#/components/schemas/UnpaperCleanEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"deskew": {
"type": "boolean",
"nullable": true,
"title": "Enables deskew"
},
"rotate_pages": {
"type": "boolean",
"nullable": true,
"title": "Enables page rotation"
},
"rotate_pages_threshold": {
"type": "number",
"format": "double",
"minimum": 0.0,
"nullable": true,
"title": "Sets the threshold for rotation of pages"
},
"max_image_pixels": {
"type": "number",
"format": "double",
"minimum": 0.0,
"nullable": true,
"title": "Sets the maximum image size for decompression"
},
"color_conversion_strategy": {
"nullable": true,
"title": "Sets the Ghostscript color conversion strategy",
"oneOf": [
{
"$ref": "#/components/schemas/ColorConversionStrategyEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"app_title": {
"type": "string",
"nullable": true,
"title": "Application title",
"maxLength": 48
},
"app_logo": {
"type": "string",
"format": "binary",
"nullable": true,
"title": "Application logo",
"pattern": "(?:jpg|png|gif|svg)$"
},
"barcodes_enabled": {
"type": "boolean",
"nullable": true,
"title": "Enables barcode scanning"
},
"barcode_enable_tiff_support": {
"type": "boolean",
"nullable": true,
"title": "Enables barcode TIFF support"
},
"barcode_string": {
"type": "string",
"nullable": true,
"title": "Sets the barcode string",
"maxLength": 32
},
"barcode_retain_split_pages": {
"type": "boolean",
"nullable": true,
"title": "Retains split pages"
},
"barcode_enable_asn": {
"type": "boolean",
"nullable": true,
"title": "Enables ASN barcode"
},
"barcode_asn_prefix": {
"type": "string",
"nullable": true,
"title": "Sets the ASN barcode prefix",
"maxLength": 32
},
"barcode_upscale": {
"type": "number",
"format": "double",
"minimum": 1.0,
"nullable": true,
"title": "Sets the barcode upscale factor"
},
"barcode_dpi": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets the barcode DPI"
},
"barcode_max_pages": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "Sets the maximum pages for barcode"
},
"barcode_enable_tag": {
"type": "boolean",
"nullable": true,
"title": "Enables tag barcode"
}
}
},
"PatchedCorrespondentRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
}
},
"PatchedCustomFieldRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"data_type": {
"$ref": "#/components/schemas/DataTypeEnum"
},
"extra_data": {
"nullable": true,
"description": "Extra data for the custom field, such as select options"
}
}
},
"PatchedDocumentRequest": {
"type": "object",
"description": "Adds update nested feature",
"properties": {
"correspondent": {
"type": "integer",
"nullable": true
},
"document_type": {
"type": "integer",
"nullable": true
},
"storage_path": {
"type": "integer",
"nullable": true
},
"title": {
"type": "string",
"maxLength": 128
},
"content": {
"type": "string",
"description": "The raw, text-only data of the document. This field is primarily used for searching."
},
"tags": {
"type": "array",
"items": {
"type": "integer"
}
},
"created": {
"type": "string",
"format": "date"
},
"created_date": {
"type": "string",
"format": "date",
"deprecated": true
},
"deleted_at": {
"type": "string",
"format": "date-time",
"nullable": true
},
"archive_serial_number": {
"type": "integer",
"maximum": 4294967295,
"minimum": 0,
"format": "int64",
"nullable": true,
"description": "The position of this document in your physical document archive."
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
},
"custom_fields": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CustomFieldInstanceRequest"
}
},
"remove_inbox_tags": {
"type": "boolean",
"writeOnly": true,
"nullable": true,
"default": false
}
}
},
"PatchedDocumentTypeRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
}
},
"PatchedGroupRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 150
},
"permissions": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
}
},
"PatchedMailAccountRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"imap_server": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"imap_port": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": -9223372036854775808,
"format": "int64",
"nullable": true,
"description": "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections."
},
"imap_security": {
"allOf": [
{
"$ref": "#/components/schemas/ImapSecurityEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"username": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"password": {
"type": "string",
"minLength": 1
},
"character_set": {
"type": "string",
"minLength": 1,
"description": "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'.",
"maxLength": 256
},
"is_token": {
"type": "boolean",
"title": "Is token authentication"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
},
"account_type": {
"allOf": [
{
"$ref": "#/components/schemas/AccountTypeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"expiration": {
"type": "string",
"format": "date-time",
"nullable": true,
"description": "The expiration date of the refresh token. "
}
}
},
"PatchedMailRuleRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"account": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"folder": {
"type": "string",
"minLength": 1,
"description": "Subfolders must be separated by a delimiter, often a dot ('.') or slash ('/'), but it varies by mail server.",
"maxLength": 256
},
"filter_from": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_to": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_subject": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_body": {
"type": "string",
"nullable": true,
"maxLength": 256
},
"filter_attachment_filename_include": {
"type": "string",
"nullable": true,
"title": "Filter attachment filename inclusive",
"description": "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"filter_attachment_filename_exclude": {
"type": "string",
"nullable": true,
"title": "Filter attachment filename exclusive",
"description": "Do not consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"maximum_age": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 0,
"format": "int64",
"description": "Specified in days."
},
"action": {
"allOf": [
{
"$ref": "#/components/schemas/MailRuleActionEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"action_parameter": {
"type": "string",
"nullable": true,
"minLength": 1,
"default": ""
},
"assign_title_from": {
"allOf": [
{
"$ref": "#/components/schemas/AssignTitleFromEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_tags": {
"type": "array",
"items": {
"type": "integer",
"nullable": true
}
},
"assign_correspondent_from": {
"allOf": [
{
"$ref": "#/components/schemas/AssignCorrespondentFromEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_correspondent": {
"type": "integer",
"nullable": true
},
"assign_document_type": {
"type": "integer",
"nullable": true
},
"assign_owner_from_rule": {
"type": "boolean",
"title": "Assign the rule owner to documents"
},
"order": {
"type": "integer"
},
"attachment_type": {
"allOf": [
{
"$ref": "#/components/schemas/AttachmentTypeEnum"
}
],
"description": "Inline attachments include embedded images, so it's best to combine this option with a filename filter.\n\n* `1` - Only process attachments.\n* `2` - Process all files, including 'inline' attachments.",
"minimum": 0,
"maximum": 9223372036854775807
},
"consumption_scope": {
"allOf": [
{
"$ref": "#/components/schemas/ConsumptionScopeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"pdf_layout": {
"allOf": [
{
"$ref": "#/components/schemas/PdfLayoutEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
}
},
"PatchedProfileRequest": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"password": {
"type": "string",
"minLength": 1
},
"first_name": {
"type": "string",
"maxLength": 150
},
"last_name": {
"type": "string",
"maxLength": 150
}
}
},
"PatchedSavedViewRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"show_on_dashboard": {
"type": "boolean"
},
"show_in_sidebar": {
"type": "boolean"
},
"sort_field": {
"type": "string",
"nullable": true,
"maxLength": 128
},
"sort_reverse": {
"type": "boolean"
},
"filter_rules": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SavedViewFilterRuleRequest"
}
},
"page_size": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "View page size"
},
"display_mode": {
"nullable": true,
"title": "View display mode",
"oneOf": [
{
"$ref": "#/components/schemas/DisplayModeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"display_fields": {
"nullable": true,
"title": "Document display fields"
},
"owner": {
"type": "integer",
"nullable": true
}
}
},
"PatchedShareLinkRequest": {
"type": "object",
"properties": {
"expiration": {
"type": "string",
"format": "date-time",
"nullable": true
},
"document": {
"type": "integer"
},
"file_version": {
"$ref": "#/components/schemas/FileVersionEnum"
}
}
},
"PatchedStoragePathRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"path": {
"type": "string",
"minLength": 1
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
}
},
"PatchedTagRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"color": {
"type": "string",
"minLength": 1,
"maxLength": 7
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"is_inbox_tag": {
"type": "boolean",
"description": "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags."
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
}
},
"PatchedUserRequest": {
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 1,
"description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
"pattern": "^[\\w.@+-]+$",
"maxLength": 150
},
"email": {
"type": "string",
"format": "email",
"title": "Email address",
"maxLength": 254
},
"password": {
"type": "string",
"minLength": 1
},
"first_name": {
"type": "string",
"maxLength": 150
},
"last_name": {
"type": "string",
"maxLength": 150
},
"date_joined": {
"type": "string",
"format": "date-time"
},
"is_staff": {
"type": "boolean",
"title": "Staff status",
"description": "Designates whether the user can log into this admin site."
},
"is_active": {
"type": "boolean",
"title": "Active",
"description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
},
"is_superuser": {
"type": "boolean",
"title": "Superuser status",
"description": "Designates that this user has all permissions without explicitly assigning them."
},
"groups": {
"type": "array",
"items": {
"type": "integer"
},
"description": "The groups this user belongs to. A user will get all permissions granted to each of their groups."
},
"user_permissions": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
}
},
"PatchedWorkflowActionRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionTypeEnum"
}
],
"title": "Workflow Action Type",
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_title": {
"type": "string",
"nullable": true,
"description": "Assign a document title, can include some placeholders, see documentation.",
"maxLength": 256
},
"assign_tags": {
"type": "array",
"items": {
"type": "integer",
"nullable": true
}
},
"assign_correspondent": {
"type": "integer",
"nullable": true
},
"assign_document_type": {
"type": "integer",
"nullable": true
},
"assign_storage_path": {
"type": "integer",
"nullable": true
},
"assign_owner": {
"type": "integer",
"nullable": true,
"title": "Assign this owner"
},
"assign_view_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant view permissions to these users"
},
"title": "Grant view permissions to these users"
},
"assign_view_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant view permissions to these groups"
},
"title": "Grant view permissions to these groups"
},
"assign_change_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant change permissions to these users"
},
"title": "Grant change permissions to these users"
},
"assign_change_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant change permissions to these groups"
},
"title": "Grant change permissions to these groups"
},
"assign_custom_fields": {
"type": "array",
"items": {
"type": "integer",
"title": "Assign these custom fields"
},
"title": "Assign these custom fields"
},
"assign_custom_fields_values": {
"nullable": true,
"title": "Custom field values",
"description": "Optional values to assign to the custom fields."
},
"remove_all_tags": {
"type": "boolean"
},
"remove_tags": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these tag(s)"
},
"title": "Remove these tag(s)"
},
"remove_all_correspondents": {
"type": "boolean"
},
"remove_correspondents": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these correspondent(s)"
},
"title": "Remove these correspondent(s)"
},
"remove_all_document_types": {
"type": "boolean"
},
"remove_document_types": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these document type(s)"
},
"title": "Remove these document type(s)"
},
"remove_all_storage_paths": {
"type": "boolean"
},
"remove_storage_paths": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these storage path(s)"
},
"title": "Remove these storage path(s)"
},
"remove_custom_fields": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these custom fields"
},
"title": "Remove these custom fields"
},
"remove_all_custom_fields": {
"type": "boolean"
},
"remove_all_owners": {
"type": "boolean"
},
"remove_owners": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these owner(s)"
},
"title": "Remove these owner(s)"
},
"remove_all_permissions": {
"type": "boolean"
},
"remove_view_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove view permissions for these users"
},
"title": "Remove view permissions for these users"
},
"remove_view_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove view permissions for these groups"
},
"title": "Remove view permissions for these groups"
},
"remove_change_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove change permissions for these users"
},
"title": "Remove change permissions for these users"
},
"remove_change_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove change permissions for these groups"
},
"title": "Remove change permissions for these groups"
},
"email": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionEmailRequest"
}
],
"nullable": true
},
"webhook": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionWebhookRequest"
}
],
"nullable": true
}
}
},
"PatchedWorkflowRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"order": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"triggers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
},
"actions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
}
}
},
"PatchedWorkflowTriggerRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"sources": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SourcesEnum"
},
"default": [
1,
2,
3
]
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowTriggerTypeEnum"
}
],
"title": "Trigger Type"
},
"filter_path": {
"type": "string",
"nullable": true,
"description": "Only consume documents with a path that matches this if specified. Wildcards specified as * are allowed. Case insensitive.",
"maxLength": 256
},
"filter_filename": {
"type": "string",
"nullable": true,
"description": "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"filter_mailrule": {
"type": "integer",
"nullable": true,
"title": "Filter documents from this mail rule"
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowTriggerMatchingAlgorithmEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"match": {
"type": "string",
"maxLength": 256
},
"is_insensitive": {
"type": "boolean"
},
"filter_has_tags": {
"type": "array",
"items": {
"type": "integer",
"title": "Has these tag(s)"
},
"title": "Has these tag(s)"
},
"filter_has_correspondent": {
"type": "integer",
"nullable": true,
"title": "Has this correspondent"
},
"filter_has_document_type": {
"type": "integer",
"nullable": true,
"title": "Has this document type"
},
"schedule_offset_days": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": -9223372036854775808,
"format": "int64",
"description": "The number of days to offset the schedule trigger by."
},
"schedule_is_recurring": {
"type": "boolean",
"description": "If the schedule should be recurring."
},
"schedule_recurring_interval_days": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"title": "Schedule recurring delay in days",
"description": "The number of days between recurring schedule triggers."
},
"schedule_date_field": {
"allOf": [
{
"$ref": "#/components/schemas/ScheduleDateFieldEnum"
}
],
"description": "The field to check for a schedule trigger.\n\n* `added` - Added\n* `created` - Created\n* `modified` - Modified\n* `custom_field` - Custom Field"
},
"schedule_date_custom_field": {
"type": "integer",
"nullable": true
}
}
},
"PdfLayoutEnum": {
"enum": [
0,
1,
2,
3,
4
],
"type": "integer",
"description": "* `0` - System default\n* `1` - Text, then HTML\n* `2` - HTML, then text\n* `3` - HTML only\n* `4` - Text only"
},
"PostDocumentRequest": {
"type": "object",
"properties": {
"created": {
"type": "string",
"format": "date-time",
"writeOnly": true,
"nullable": true
},
"document": {
"type": "string",
"format": "binary",
"writeOnly": true
},
"title": {
"type": "string",
"writeOnly": true,
"minLength": 1
},
"correspondent": {
"type": "integer",
"writeOnly": true,
"nullable": true
},
"document_type": {
"type": "integer",
"writeOnly": true,
"nullable": true
},
"storage_path": {
"type": "integer",
"writeOnly": true,
"nullable": true
},
"tags": {
"type": "array",
"items": {
"type": "integer",
"writeOnly": true,
"title": "Tags"
},
"writeOnly": true
},
"archive_serial_number": {
"type": "integer",
"maximum": 4294967295,
"minimum": 0,
"format": "int64",
"writeOnly": true,
"title": "ASN"
},
"custom_fields": {
"type": "array",
"items": {
"type": "integer",
"writeOnly": true,
"title": "Custom fields"
},
"writeOnly": true
},
"from_webui": {
"type": "boolean",
"writeOnly": true,
"title": "Documents are from Paperless-ngx WebUI"
}
},
"required": [
"document"
]
},
"Profile": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"password": {
"type": "string"
},
"first_name": {
"type": "string",
"maxLength": 150
},
"last_name": {
"type": "string",
"maxLength": 150
},
"auth_token": {
"type": "string",
"readOnly": true
},
"social_accounts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SocialAccount"
},
"readOnly": true
},
"has_usable_password": {
"type": "boolean",
"readOnly": true
},
"is_mfa_enabled": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"auth_token",
"has_usable_password",
"is_mfa_enabled",
"social_accounts"
]
},
"RuleTypeEnum": {
"enum": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47
],
"type": "integer",
"description": "* `0` - title contains\n* `1` - content contains\n* `2` - ASN is\n* `3` - correspondent is\n* `4` - document type is\n* `5` - is in inbox\n* `6` - has tag\n* `7` - has any tag\n* `8` - created before\n* `9` - created after\n* `10` - created year is\n* `11` - created month is\n* `12` - created day is\n* `13` - added before\n* `14` - added after\n* `15` - modified before\n* `16` - modified after\n* `17` - does not have tag\n* `18` - does not have ASN\n* `19` - title or content contains\n* `20` - fulltext query\n* `21` - more like this\n* `22` - has tags in\n* `23` - ASN greater than\n* `24` - ASN less than\n* `25` - storage path is\n* `26` - has correspondent in\n* `27` - does not have correspondent in\n* `28` - has document type in\n* `29` - does not have document type in\n* `30` - has storage path in\n* `31` - does not have storage path in\n* `32` - owner is\n* `33` - has owner in\n* `34` - does not have owner\n* `35` - does not have owner in\n* `36` - has custom field value\n* `37` - is shared by me\n* `38` - has custom fields\n* `39` - has custom field in\n* `40` - does not have custom field in\n* `41` - does not have custom field\n* `42` - custom fields query\n* `43` - created to\n* `44` - created from\n* `45` - added to\n* `46` - added from\n* `47` - mime type is"
},
"SanityCheck": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"error": {
"type": "string"
},
"last_run": {
"type": "string",
"format": "date-time"
}
},
"required": [
"error",
"last_run",
"status"
]
},
"SavedView": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 128
},
"show_on_dashboard": {
"type": "boolean"
},
"show_in_sidebar": {
"type": "boolean"
},
"sort_field": {
"type": "string",
"nullable": true,
"maxLength": 128
},
"sort_reverse": {
"type": "boolean"
},
"filter_rules": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SavedViewFilterRule"
}
},
"page_size": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "View page size"
},
"display_mode": {
"nullable": true,
"title": "View display mode",
"oneOf": [
{
"$ref": "#/components/schemas/DisplayModeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"display_fields": {
"nullable": true,
"title": "Document display fields"
},
"owner": {
"type": "integer",
"nullable": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"filter_rules",
"id",
"name",
"show_in_sidebar",
"show_on_dashboard",
"user_can_change"
]
},
"SavedViewFilterRule": {
"type": "object",
"properties": {
"rule_type": {
"allOf": [
{
"$ref": "#/components/schemas/RuleTypeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"value": {
"type": "string",
"nullable": true,
"maxLength": 255
}
},
"required": [
"rule_type"
]
},
"SavedViewFilterRuleRequest": {
"type": "object",
"properties": {
"rule_type": {
"allOf": [
{
"$ref": "#/components/schemas/RuleTypeEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"value": {
"type": "string",
"nullable": true,
"maxLength": 255
}
},
"required": [
"rule_type"
]
},
"SavedViewRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"show_on_dashboard": {
"type": "boolean"
},
"show_in_sidebar": {
"type": "boolean"
},
"sort_field": {
"type": "string",
"nullable": true,
"maxLength": 128
},
"sort_reverse": {
"type": "boolean"
},
"filter_rules": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SavedViewFilterRuleRequest"
}
},
"page_size": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"nullable": true,
"title": "View page size"
},
"display_mode": {
"nullable": true,
"title": "View display mode",
"oneOf": [
{
"$ref": "#/components/schemas/DisplayModeEnum"
},
{
"$ref": "#/components/schemas/BlankEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"display_fields": {
"nullable": true,
"title": "Document display fields"
},
"owner": {
"type": "integer",
"nullable": true
}
},
"required": [
"filter_rules",
"name",
"show_in_sidebar",
"show_on_dashboard"
]
},
"ScheduleDateFieldEnum": {
"enum": [
"added",
"created",
"modified",
"custom_field"
],
"type": "string",
"description": "* `added` - Added\n* `created` - Created\n* `modified` - Modified\n* `custom_field` - Custom Field"
},
"SearchResult": {
"type": "object",
"properties": {
"total": {
"type": "integer"
},
"documents": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Document"
}
},
"saved_views": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SavedView"
}
},
"tags": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Tag"
}
},
"correspondents": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Correspondent"
}
},
"document_types": {
"type": "array",
"items": {
"$ref": "#/components/schemas/DocumentType"
}
},
"storage_paths": {
"type": "array",
"items": {
"$ref": "#/components/schemas/StoragePath"
}
},
"users": {
"type": "array",
"items": {
"$ref": "#/components/schemas/User"
}
},
"groups": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Group"
}
},
"mail_rules": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MailRule"
}
},
"mail_accounts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MailAccount"
}
},
"workflows": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Workflow"
}
},
"custom_fields": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CustomField"
}
}
},
"required": [
"correspondents",
"custom_fields",
"document_types",
"documents",
"groups",
"mail_accounts",
"mail_rules",
"saved_views",
"storage_paths",
"tags",
"total",
"users",
"workflows"
]
},
"SelectionData": {
"type": "object",
"properties": {
"selected_correspondents": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CorrespondentCounts"
}
},
"selected_tags": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TagCounts"
}
},
"selected_document_types": {
"type": "array",
"items": {
"$ref": "#/components/schemas/DocumentTypeCounts"
}
},
"selected_storage_paths": {
"type": "array",
"items": {
"$ref": "#/components/schemas/StoragePathCounts"
}
},
"selected_custom_fields": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CustomFieldCounts"
}
}
},
"required": [
"selected_correspondents",
"selected_custom_fields",
"selected_document_types",
"selected_storage_paths",
"selected_tags"
]
},
"ShareLink": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"created": {
"type": "string",
"format": "date-time",
"readOnly": true
},
"expiration": {
"type": "string",
"format": "date-time",
"nullable": true
},
"slug": {
"type": "string",
"readOnly": true,
"pattern": "^[-a-zA-Z0-9_]+$"
},
"document": {
"type": "integer"
},
"file_version": {
"$ref": "#/components/schemas/FileVersionEnum"
}
},
"required": [
"created",
"id",
"slug"
]
},
"ShareLinkRequest": {
"type": "object",
"properties": {
"expiration": {
"type": "string",
"format": "date-time",
"nullable": true
},
"document": {
"type": "integer"
},
"file_version": {
"$ref": "#/components/schemas/FileVersionEnum"
}
}
},
"SkipArchiveFileEnum": {
"enum": [
"never",
"with_text",
"always"
],
"type": "string",
"description": "* `never` - never\n* `with_text` - with_text\n* `always` - always"
},
"SocialAccount": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"provider": {
"type": "string",
"maxLength": 200
},
"name": {
"type": "string",
"readOnly": true
}
},
"required": [
"id",
"name",
"provider"
]
},
"SocialAccountRequest": {
"type": "object",
"properties": {
"provider": {
"type": "string",
"minLength": 1,
"maxLength": 200
}
},
"required": [
"provider"
]
},
"SourcesEnum": {
"enum": [
1,
2,
3,
4
],
"type": "integer",
"description": "* `1` - Consume Folder\n* `2` - Api Upload\n* `3` - Mail Fetch\n* `4` - Web UI"
},
"StatusEnum": {
"enum": [
"FAILURE",
"PENDING",
"RECEIVED",
"RETRY",
"REVOKED",
"STARTED",
"SUCCESS"
],
"type": "string",
"description": "* `FAILURE` - FAILURE\n* `PENDING` - PENDING\n* `RECEIVED` - RECEIVED\n* `RETRY` - RETRY\n* `REVOKED` - REVOKED\n* `STARTED` - STARTED\n* `SUCCESS` - SUCCESS"
},
"Storage": {
"type": "object",
"properties": {
"total": {
"type": "integer"
},
"available": {
"type": "integer"
}
},
"required": [
"available",
"total"
]
},
"StoragePath": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"slug": {
"type": "string",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 128
},
"path": {
"type": "string"
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"document_count": {
"type": "integer",
"readOnly": true
},
"owner": {
"type": "integer",
"nullable": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"document_count",
"id",
"name",
"path",
"slug",
"user_can_change"
]
},
"StoragePathCounts": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"document_count": {
"type": "integer"
}
},
"required": [
"document_count",
"id"
]
},
"StoragePathRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"path": {
"type": "string",
"minLength": 1
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
},
"required": [
"name",
"path"
]
},
"Suggestions": {
"type": "object",
"properties": {
"correspondents": {
"type": "array",
"items": {
"type": "integer"
}
},
"tags": {
"type": "array",
"items": {
"type": "integer"
}
},
"document_types": {
"type": "array",
"items": {
"type": "integer"
}
},
"storage_paths": {
"type": "array",
"items": {
"type": "integer"
}
},
"dates": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"correspondents",
"dates",
"document_types",
"storage_paths",
"tags"
]
},
"SystemStatus": {
"type": "object",
"properties": {
"pngx_version": {
"type": "string"
},
"server_os": {
"type": "string"
},
"install_type": {
"type": "string"
},
"storage": {
"$ref": "#/components/schemas/Storage"
},
"database": {
"$ref": "#/components/schemas/Database"
},
"tasks": {
"$ref": "#/components/schemas/Tasks"
},
"index": {
"$ref": "#/components/schemas/Index"
},
"classifier": {
"$ref": "#/components/schemas/Classifier"
},
"sanity_check": {
"$ref": "#/components/schemas/SanityCheck"
}
},
"required": [
"classifier",
"database",
"index",
"install_type",
"pngx_version",
"sanity_check",
"server_os",
"storage",
"tasks"
]
},
"Tag": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"slug": {
"type": "string",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 128
},
"color": {
"type": "string",
"maxLength": 7
},
"text_color": {
"type": "string",
"readOnly": true
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"is_inbox_tag": {
"type": "boolean",
"description": "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags."
},
"document_count": {
"type": "integer",
"readOnly": true
},
"owner": {
"type": "integer",
"nullable": true
},
"user_can_change": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"document_count",
"id",
"name",
"slug",
"text_color",
"user_can_change"
]
},
"TagCounts": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"document_count": {
"type": "integer"
}
},
"required": [
"document_count",
"id"
]
},
"TagRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"color": {
"type": "string",
"minLength": 1,
"maxLength": 7
},
"match": {
"type": "string",
"maxLength": 256
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/MatchingAlgorithm"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"is_insensitive": {
"type": "boolean"
},
"is_inbox_tag": {
"type": "boolean",
"description": "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags."
},
"owner": {
"type": "integer",
"nullable": true
},
"set_permissions": {
"type": "object",
"properties": {
"view": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"change": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "integer"
}
},
"groups": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
},
"writeOnly": true
}
},
"required": [
"name"
]
},
"TaskNameEnum": {
"enum": [
"consume_file",
"train_classifier",
"check_sanity",
"index_optimize"
],
"type": "string",
"description": "* `consume_file` - Consume File\n* `train_classifier` - Train Classifier\n* `check_sanity` - Check Sanity\n* `index_optimize` - Index Optimize"
},
"Tasks": {
"type": "object",
"properties": {
"redis_url": {
"type": "string"
},
"redis_status": {
"type": "string"
},
"redis_error": {
"type": "string"
},
"celery_status": {
"type": "string"
}
},
"required": [
"celery_status",
"redis_error",
"redis_status",
"redis_url"
]
},
"TasksView": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"task_id": {
"type": "string",
"description": "Celery ID for the Task that was run",
"maxLength": 255
},
"task_name": {
"nullable": true,
"description": "Name of the task that was run\n\n* `consume_file` - Consume File\n* `train_classifier` - Train Classifier\n* `check_sanity` - Check Sanity\n* `index_optimize` - Index Optimize",
"oneOf": [
{
"$ref": "#/components/schemas/TaskNameEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"task_file_name": {
"type": "string",
"nullable": true,
"title": "Task Filename",
"description": "Name of the file which the Task was run for",
"maxLength": 255
},
"date_created": {
"type": "string",
"format": "date-time",
"nullable": true,
"title": "Created DateTime",
"description": "Datetime field when the task result was created in UTC"
},
"date_done": {
"type": "string",
"format": "date-time",
"nullable": true,
"title": "Completed DateTime",
"description": "Datetime field when the task was completed in UTC"
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/TasksViewTypeEnum"
}
],
"title": "Task Type",
"description": "The type of task that was run\n\n* `auto_task` - Auto Task\n* `scheduled_task` - Scheduled Task\n* `manual_task` - Manual Task"
},
"status": {
"allOf": [
{
"$ref": "#/components/schemas/StatusEnum"
}
],
"title": "Task State",
"description": "Current state of the task being run\n\n* `FAILURE` - FAILURE\n* `PENDING` - PENDING\n* `RECEIVED` - RECEIVED\n* `RETRY` - RETRY\n* `REVOKED` - REVOKED\n* `STARTED` - STARTED\n* `SUCCESS` - SUCCESS"
},
"result": {
"type": "string",
"nullable": true,
"title": "Result Data",
"description": "The data returned by the task"
},
"acknowledged": {
"type": "boolean",
"description": "If the task is acknowledged via the frontend or API"
},
"related_document": {
"type": "string",
"nullable": true,
"readOnly": true
},
"owner": {
"type": "integer",
"nullable": true
}
},
"required": [
"id",
"related_document",
"task_id"
]
},
"TasksViewRequest": {
"type": "object",
"properties": {
"task_id": {
"type": "string",
"minLength": 1,
"description": "Celery ID for the Task that was run",
"maxLength": 255
},
"task_name": {
"nullable": true,
"description": "Name of the task that was run\n\n* `consume_file` - Consume File\n* `train_classifier` - Train Classifier\n* `check_sanity` - Check Sanity\n* `index_optimize` - Index Optimize",
"oneOf": [
{
"$ref": "#/components/schemas/TaskNameEnum"
},
{
"$ref": "#/components/schemas/NullEnum"
}
]
},
"task_file_name": {
"type": "string",
"nullable": true,
"minLength": 1,
"title": "Task Filename",
"description": "Name of the file which the Task was run for",
"maxLength": 255
},
"date_created": {
"type": "string",
"format": "date-time",
"nullable": true,
"title": "Created DateTime",
"description": "Datetime field when the task result was created in UTC"
},
"date_done": {
"type": "string",
"format": "date-time",
"nullable": true,
"title": "Completed DateTime",
"description": "Datetime field when the task was completed in UTC"
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/TasksViewTypeEnum"
}
],
"title": "Task Type",
"description": "The type of task that was run\n\n* `auto_task` - Auto Task\n* `scheduled_task` - Scheduled Task\n* `manual_task` - Manual Task"
},
"status": {
"allOf": [
{
"$ref": "#/components/schemas/StatusEnum"
}
],
"title": "Task State",
"description": "Current state of the task being run\n\n* `FAILURE` - FAILURE\n* `PENDING` - PENDING\n* `RECEIVED` - RECEIVED\n* `RETRY` - RETRY\n* `REVOKED` - REVOKED\n* `STARTED` - STARTED\n* `SUCCESS` - SUCCESS"
},
"result": {
"type": "string",
"nullable": true,
"minLength": 1,
"title": "Result Data",
"description": "The data returned by the task"
},
"acknowledged": {
"type": "boolean",
"description": "If the task is acknowledged via the frontend or API"
},
"owner": {
"type": "integer",
"nullable": true
}
},
"required": [
"task_id"
]
},
"TasksViewTypeEnum": {
"enum": [
"auto_task",
"scheduled_task",
"manual_task"
],
"type": "string",
"description": "* `auto_task` - Auto Task\n* `scheduled_task` - Scheduled Task\n* `manual_task` - Manual Task"
},
"TrashActionEnum": {
"enum": [
"restore",
"empty"
],
"type": "string",
"description": "* `restore` - restore\n* `empty` - empty"
},
"TrashRequest": {
"type": "object",
"properties": {
"documents": {
"type": "array",
"items": {
"type": "integer"
},
"writeOnly": true
},
"action": {
"allOf": [
{
"$ref": "#/components/schemas/TrashActionEnum"
}
],
"writeOnly": true
}
},
"required": [
"action"
]
},
"UiSettingsView": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"settings": {
"type": "object",
"additionalProperties": {},
"nullable": true
}
},
"required": [
"id"
]
},
"UiSettingsViewRequest": {
"type": "object",
"properties": {
"settings": {
"type": "object",
"additionalProperties": {},
"nullable": true
}
}
},
"UnpaperCleanEnum": {
"enum": [
"clean",
"clean-final",
"none"
],
"type": "string",
"description": "* `clean` - clean\n* `clean-final` - clean-final\n* `none` - none"
},
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"username": {
"type": "string",
"description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
"pattern": "^[\\w.@+-]+$",
"maxLength": 150
},
"email": {
"type": "string",
"format": "email",
"title": "Email address",
"maxLength": 254
},
"password": {
"type": "string"
},
"first_name": {
"type": "string",
"maxLength": 150
},
"last_name": {
"type": "string",
"maxLength": 150
},
"date_joined": {
"type": "string",
"format": "date-time"
},
"is_staff": {
"type": "boolean",
"title": "Staff status",
"description": "Designates whether the user can log into this admin site."
},
"is_active": {
"type": "boolean",
"title": "Active",
"description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
},
"is_superuser": {
"type": "boolean",
"title": "Superuser status",
"description": "Designates that this user has all permissions without explicitly assigning them."
},
"groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Groups"
},
"description": "The groups this user belongs to. A user will get all permissions granted to each of their groups."
},
"user_permissions": {
"type": "array",
"items": {
"type": "string"
}
},
"inherited_permissions": {
"type": "array",
"items": {
"type": "string"
},
"readOnly": true
},
"is_mfa_enabled": {
"type": "boolean",
"readOnly": true
}
},
"required": [
"id",
"inherited_permissions",
"is_mfa_enabled",
"username"
]
},
"UserRequest": {
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 1,
"description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
"pattern": "^[\\w.@+-]+$",
"maxLength": 150
},
"email": {
"type": "string",
"format": "email",
"title": "Email address",
"maxLength": 254
},
"password": {
"type": "string",
"minLength": 1
},
"first_name": {
"type": "string",
"maxLength": 150
},
"last_name": {
"type": "string",
"maxLength": 150
},
"date_joined": {
"type": "string",
"format": "date-time"
},
"is_staff": {
"type": "boolean",
"title": "Staff status",
"description": "Designates whether the user can log into this admin site."
},
"is_active": {
"type": "boolean",
"title": "Active",
"description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
},
"is_superuser": {
"type": "boolean",
"title": "Superuser status",
"description": "Designates that this user has all permissions without explicitly assigning them."
},
"groups": {
"type": "array",
"items": {
"type": "integer"
},
"description": "The groups this user belongs to. A user will get all permissions granted to each of their groups."
},
"user_permissions": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
},
"required": [
"username"
]
},
"Workflow": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"readOnly": true
},
"name": {
"type": "string",
"maxLength": 256
},
"order": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"triggers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowTrigger"
}
},
"actions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowAction"
}
}
},
"required": [
"actions",
"id",
"name",
"triggers"
]
},
"WorkflowAction": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionTypeEnum"
}
],
"title": "Workflow Action Type",
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_title": {
"type": "string",
"nullable": true,
"description": "Assign a document title, can include some placeholders, see documentation.",
"maxLength": 256
},
"assign_tags": {
"type": "array",
"items": {
"type": "integer",
"nullable": true
}
},
"assign_correspondent": {
"type": "integer",
"nullable": true
},
"assign_document_type": {
"type": "integer",
"nullable": true
},
"assign_storage_path": {
"type": "integer",
"nullable": true
},
"assign_owner": {
"type": "integer",
"nullable": true,
"title": "Assign this owner"
},
"assign_view_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant view permissions to these users"
},
"title": "Grant view permissions to these users"
},
"assign_view_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant view permissions to these groups"
},
"title": "Grant view permissions to these groups"
},
"assign_change_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant change permissions to these users"
},
"title": "Grant change permissions to these users"
},
"assign_change_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant change permissions to these groups"
},
"title": "Grant change permissions to these groups"
},
"assign_custom_fields": {
"type": "array",
"items": {
"type": "integer",
"title": "Assign these custom fields"
},
"title": "Assign these custom fields"
},
"assign_custom_fields_values": {
"nullable": true,
"title": "Custom field values",
"description": "Optional values to assign to the custom fields."
},
"remove_all_tags": {
"type": "boolean"
},
"remove_tags": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these tag(s)"
},
"title": "Remove these tag(s)"
},
"remove_all_correspondents": {
"type": "boolean"
},
"remove_correspondents": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these correspondent(s)"
},
"title": "Remove these correspondent(s)"
},
"remove_all_document_types": {
"type": "boolean"
},
"remove_document_types": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these document type(s)"
},
"title": "Remove these document type(s)"
},
"remove_all_storage_paths": {
"type": "boolean"
},
"remove_storage_paths": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these storage path(s)"
},
"title": "Remove these storage path(s)"
},
"remove_custom_fields": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these custom fields"
},
"title": "Remove these custom fields"
},
"remove_all_custom_fields": {
"type": "boolean"
},
"remove_all_owners": {
"type": "boolean"
},
"remove_owners": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these owner(s)"
},
"title": "Remove these owner(s)"
},
"remove_all_permissions": {
"type": "boolean"
},
"remove_view_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove view permissions for these users"
},
"title": "Remove view permissions for these users"
},
"remove_view_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove view permissions for these groups"
},
"title": "Remove view permissions for these groups"
},
"remove_change_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove change permissions for these users"
},
"title": "Remove change permissions for these users"
},
"remove_change_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove change permissions for these groups"
},
"title": "Remove change permissions for these groups"
},
"email": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionEmail"
}
],
"nullable": true
},
"webhook": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionWebhook"
}
],
"nullable": true
}
}
},
"WorkflowActionEmail": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"subject": {
"type": "string",
"title": "Email subject",
"description": "The subject of the email, can include some placeholders, see documentation.",
"maxLength": 256
},
"body": {
"type": "string",
"title": "Email body",
"description": "The body (message) of the email, can include some placeholders, see documentation."
},
"to": {
"type": "string",
"title": "Emails to",
"description": "The destination email addresses, comma separated."
},
"include_document": {
"type": "boolean",
"title": "Include document in email"
}
},
"required": [
"body",
"subject",
"to"
]
},
"WorkflowActionEmailRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"subject": {
"type": "string",
"minLength": 1,
"title": "Email subject",
"description": "The subject of the email, can include some placeholders, see documentation.",
"maxLength": 256
},
"body": {
"type": "string",
"minLength": 1,
"title": "Email body",
"description": "The body (message) of the email, can include some placeholders, see documentation."
},
"to": {
"type": "string",
"minLength": 1,
"title": "Emails to",
"description": "The destination email addresses, comma separated."
},
"include_document": {
"type": "boolean",
"title": "Include document in email"
}
},
"required": [
"body",
"subject",
"to"
]
},
"WorkflowActionRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionTypeEnum"
}
],
"title": "Workflow Action Type",
"minimum": 0,
"maximum": 9223372036854775807
},
"assign_title": {
"type": "string",
"nullable": true,
"description": "Assign a document title, can include some placeholders, see documentation.",
"maxLength": 256
},
"assign_tags": {
"type": "array",
"items": {
"type": "integer",
"nullable": true
}
},
"assign_correspondent": {
"type": "integer",
"nullable": true
},
"assign_document_type": {
"type": "integer",
"nullable": true
},
"assign_storage_path": {
"type": "integer",
"nullable": true
},
"assign_owner": {
"type": "integer",
"nullable": true,
"title": "Assign this owner"
},
"assign_view_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant view permissions to these users"
},
"title": "Grant view permissions to these users"
},
"assign_view_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant view permissions to these groups"
},
"title": "Grant view permissions to these groups"
},
"assign_change_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant change permissions to these users"
},
"title": "Grant change permissions to these users"
},
"assign_change_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Grant change permissions to these groups"
},
"title": "Grant change permissions to these groups"
},
"assign_custom_fields": {
"type": "array",
"items": {
"type": "integer",
"title": "Assign these custom fields"
},
"title": "Assign these custom fields"
},
"assign_custom_fields_values": {
"nullable": true,
"title": "Custom field values",
"description": "Optional values to assign to the custom fields."
},
"remove_all_tags": {
"type": "boolean"
},
"remove_tags": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these tag(s)"
},
"title": "Remove these tag(s)"
},
"remove_all_correspondents": {
"type": "boolean"
},
"remove_correspondents": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these correspondent(s)"
},
"title": "Remove these correspondent(s)"
},
"remove_all_document_types": {
"type": "boolean"
},
"remove_document_types": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these document type(s)"
},
"title": "Remove these document type(s)"
},
"remove_all_storage_paths": {
"type": "boolean"
},
"remove_storage_paths": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these storage path(s)"
},
"title": "Remove these storage path(s)"
},
"remove_custom_fields": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these custom fields"
},
"title": "Remove these custom fields"
},
"remove_all_custom_fields": {
"type": "boolean"
},
"remove_all_owners": {
"type": "boolean"
},
"remove_owners": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove these owner(s)"
},
"title": "Remove these owner(s)"
},
"remove_all_permissions": {
"type": "boolean"
},
"remove_view_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove view permissions for these users"
},
"title": "Remove view permissions for these users"
},
"remove_view_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove view permissions for these groups"
},
"title": "Remove view permissions for these groups"
},
"remove_change_users": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove change permissions for these users"
},
"title": "Remove change permissions for these users"
},
"remove_change_groups": {
"type": "array",
"items": {
"type": "integer",
"title": "Remove change permissions for these groups"
},
"title": "Remove change permissions for these groups"
},
"email": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionEmailRequest"
}
],
"nullable": true
},
"webhook": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowActionWebhookRequest"
}
],
"nullable": true
}
}
},
"WorkflowActionTypeEnum": {
"enum": [
1,
2,
3,
4
],
"type": "integer",
"description": "* `1` - Assignment\n* `2` - Removal\n* `3` - Email\n* `4` - Webhook"
},
"WorkflowActionWebhook": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"url": {
"type": "string",
"title": "Webhook url",
"description": "The destination URL for the notification.",
"maxLength": 256
},
"use_params": {
"type": "boolean",
"title": "Use parameters"
},
"as_json": {
"type": "boolean",
"title": "Send as JSON"
},
"params": {
"nullable": true,
"title": "Webhook parameters",
"description": "The parameters to send with the webhook URL if body not used."
},
"body": {
"type": "string",
"nullable": true,
"title": "Webhook body",
"description": "The body to send with the webhook URL if parameters not used."
},
"headers": {
"nullable": true,
"title": "Webhook headers",
"description": "The headers to send with the webhook URL."
},
"include_document": {
"type": "boolean",
"title": "Include document in webhook"
}
},
"required": [
"url"
]
},
"WorkflowActionWebhookRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"url": {
"type": "string",
"minLength": 1,
"title": "Webhook url",
"description": "The destination URL for the notification.",
"maxLength": 256
},
"use_params": {
"type": "boolean",
"title": "Use parameters"
},
"as_json": {
"type": "boolean",
"title": "Send as JSON"
},
"params": {
"nullable": true,
"title": "Webhook parameters",
"description": "The parameters to send with the webhook URL if body not used."
},
"body": {
"type": "string",
"nullable": true,
"title": "Webhook body",
"description": "The body to send with the webhook URL if parameters not used."
},
"headers": {
"nullable": true,
"title": "Webhook headers",
"description": "The headers to send with the webhook URL."
},
"include_document": {
"type": "boolean",
"title": "Include document in webhook"
}
},
"required": [
"url"
]
},
"WorkflowRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"order": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"triggers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowTriggerRequest"
}
},
"actions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WorkflowActionRequest"
}
}
},
"required": [
"actions",
"name",
"triggers"
]
},
"WorkflowTrigger": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"sources": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SourcesEnum"
},
"default": [
1,
2,
3
]
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowTriggerTypeEnum"
}
],
"title": "Trigger Type"
},
"filter_path": {
"type": "string",
"nullable": true,
"description": "Only consume documents with a path that matches this if specified. Wildcards specified as * are allowed. Case insensitive.",
"maxLength": 256
},
"filter_filename": {
"type": "string",
"nullable": true,
"description": "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"filter_mailrule": {
"type": "integer",
"nullable": true,
"title": "Filter documents from this mail rule"
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowTriggerMatchingAlgorithmEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"match": {
"type": "string",
"maxLength": 256
},
"is_insensitive": {
"type": "boolean"
},
"filter_has_tags": {
"type": "array",
"items": {
"type": "integer",
"title": "Has these tag(s)"
},
"title": "Has these tag(s)"
},
"filter_has_correspondent": {
"type": "integer",
"nullable": true,
"title": "Has this correspondent"
},
"filter_has_document_type": {
"type": "integer",
"nullable": true,
"title": "Has this document type"
},
"schedule_offset_days": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": -9223372036854775808,
"format": "int64",
"description": "The number of days to offset the schedule trigger by."
},
"schedule_is_recurring": {
"type": "boolean",
"description": "If the schedule should be recurring."
},
"schedule_recurring_interval_days": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"title": "Schedule recurring delay in days",
"description": "The number of days between recurring schedule triggers."
},
"schedule_date_field": {
"allOf": [
{
"$ref": "#/components/schemas/ScheduleDateFieldEnum"
}
],
"description": "The field to check for a schedule trigger.\n\n* `added` - Added\n* `created` - Created\n* `modified` - Modified\n* `custom_field` - Custom Field"
},
"schedule_date_custom_field": {
"type": "integer",
"nullable": true
}
},
"required": [
"type"
]
},
"WorkflowTriggerMatchingAlgorithmEnum": {
"enum": [
0,
1,
2,
3,
4,
5
],
"type": "integer",
"description": "* `0` - None\n* `1` - Any word\n* `2` - All words\n* `3` - Exact match\n* `4` - Regular expression\n* `5` - Fuzzy word"
},
"WorkflowTriggerRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"nullable": true
},
"sources": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SourcesEnum"
},
"default": [
1,
2,
3
]
},
"type": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowTriggerTypeEnum"
}
],
"title": "Trigger Type"
},
"filter_path": {
"type": "string",
"nullable": true,
"description": "Only consume documents with a path that matches this if specified. Wildcards specified as * are allowed. Case insensitive.",
"maxLength": 256
},
"filter_filename": {
"type": "string",
"nullable": true,
"description": "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.",
"maxLength": 256
},
"filter_mailrule": {
"type": "integer",
"nullable": true,
"title": "Filter documents from this mail rule"
},
"matching_algorithm": {
"allOf": [
{
"$ref": "#/components/schemas/WorkflowTriggerMatchingAlgorithmEnum"
}
],
"minimum": 0,
"maximum": 9223372036854775807
},
"match": {
"type": "string",
"maxLength": 256
},
"is_insensitive": {
"type": "boolean"
},
"filter_has_tags": {
"type": "array",
"items": {
"type": "integer",
"title": "Has these tag(s)"
},
"title": "Has these tag(s)"
},
"filter_has_correspondent": {
"type": "integer",
"nullable": true,
"title": "Has this correspondent"
},
"filter_has_document_type": {
"type": "integer",
"nullable": true,
"title": "Has this document type"
},
"schedule_offset_days": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": -9223372036854775808,
"format": "int64",
"description": "The number of days to offset the schedule trigger by."
},
"schedule_is_recurring": {
"type": "boolean",
"description": "If the schedule should be recurring."
},
"schedule_recurring_interval_days": {
"type": "integer",
"maximum": 9223372036854775807,
"minimum": 1,
"format": "int64",
"title": "Schedule recurring delay in days",
"description": "The number of days between recurring schedule triggers."
},
"schedule_date_field": {
"allOf": [
{
"$ref": "#/components/schemas/ScheduleDateFieldEnum"
}
],
"description": "The field to check for a schedule trigger.\n\n* `added` - Added\n* `created` - Created\n* `modified` - Modified\n* `custom_field` - Custom Field"
},
"schedule_date_custom_field": {
"type": "integer",
"nullable": true
}
},
"required": [
"type"
]
},
"WorkflowTriggerTypeEnum": {
"enum": [
1,
2,
3,
4
],
"type": "integer",
"description": "* `1` - Consumption Started\n* `2` - Document Added\n* `3` - Document Updated\n* `4` - Scheduled"
}
},
"securitySchemes": {
"PaperelessBasicAuthentication": {
"type": "http",
"scheme": "basic"
},
"cookieAuth": {
"type": "apiKey",
"in": "cookie",
"name": "sessionid"
},
"tokenAuth": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Token-based authentication with required prefix \"Token\""
}
}
},
"externalDocs": {
"description": "Paperless-ngx API Documentation",
"url": "https://docs.paperless-ngx.com/api/"
}
}
paperless-api-5.1.0/tests/data/share_links.py 0000664 0000000 0000000 00000004534 15053074171 0021222 0 ustar 00root root 0000000 0000000 """Share links snapshot."""
DATA_SHARE_LINKS = {
"count": 5,
"next": None,
"previous": None,
"all": [1, 2, 3, 4, 5, 6, 7, 8],
"results": [
{
"id": 1,
"created": "2023-12-11T14:06:49.096456Z",
"expiration": "2023-12-18T14:06:49.064000Z",
"slug": "GMIFR9WVPe7a0FAltmrAdmVsrrTzH6Z9yFi2jufhi5yCTAMWfF",
"document": 1,
"file_version": "original",
},
{
"id": 2,
"created": "2023-12-11T14:06:53.583496Z",
"expiration": "2024-01-10T14:06:53.558000Z",
"slug": "Px2h3mrkIvExyTE8M8usrTLv3jtTb4MnLJ4eTAxcjy2FUmuDLq",
"document": 2,
"file_version": "original",
},
{
"id": 3,
"created": "2023-12-11T14:06:55.984583Z",
"expiration": None,
"slug": "bDnxeQ4UmlFVUYCDrb1KBLbE4HVSW8jw3CLElcwPyAncV5eiI+00:00",
"document": 1,
"file_version": "original",
},
{
"id": 4,
"created": "2023-12-11T14:07:01.448813Z",
"expiration": "2023-12-12T14:07:01.423000Z",
"slug": "HfzHhDzA03ZQg4t4TAlOuup59qgQA18Zjbb9eOE06PZ8KTjgOb",
"document": 2,
"file_version": "archive",
},
{
"id": 5,
"created": "2023-12-11T14:11:50.710369Z",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
{
"id": 6,
"created": "2023-12-11T14:11:50.710369Z",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
{
"id": 7,
"created": "2023-12-11T14:11:50.710369Z",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
{
"id": 8,
"created": "2023-12-11T14:11:50.710369Z",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
],
}
paperless-api-5.1.0/tests/data/statistics.py 0000664 0000000 0000000 00000001042 15053074171 0021101 0 ustar 00root root 0000000 0000000 """Statistics snapshot."""
DATA_STATISTICS = {
"documents_total": 1337,
"documents_inbox": 2,
"inbox_tag": 1,
"inbox_tags": [1],
"document_file_type_counts": [
{"mime_type": "application/pdf", "mime_type_count": 1334},
{"mime_type": "image/jpeg", "mime_type_count": 2},
{"mime_type": "message/rfc822", "mime_type_count": 1},
],
"character_count": 13371337,
"tag_count": 5,
"correspondent_count": 42,
"document_type_count": 23,
"storage_path_count": 5,
"current_asn": 84,
}
paperless-api-5.1.0/tests/data/status.py 0000664 0000000 0000000 00000001760 15053074171 0020241 0 ustar 00root root 0000000 0000000 """Status snapshot."""
DATA_STATUS = {
"pngx_version": "2.6.1",
"server_os": "Linux-6.6.12-linuxkit-aarch64-with-glibc2.36",
"install_type": "docker",
"storage": {
"total": 494384795648,
"available": 103324229632,
},
"database": {
"type": "sqlite",
"url": "/usr/src/paperless/data/db.sqlite3",
"status": "OK",
"error": None,
"migration_status": {
"latest_migration": "paperless.0003_alter_applicationconfiguration_max_image_pixels",
"unapplied_migrations": [],
},
},
"tasks": {
"redis_url": "redis://broker:6379",
"redis_status": "OK",
"redis_error": None,
"celery_status": "OK",
"index_status": "OK",
"index_last_modified": "2024-03-06T07:10:55.370884+01:00",
"index_error": None,
"classifier_status": "OK",
"classifier_last_trained": "2024-03-06T07:05:01.281804+00:00",
"classifier_error": None,
},
}
paperless-api-5.1.0/tests/data/storage_paths.py 0000664 0000000 0000000 00000003745 15053074171 0021566 0 ustar 00root root 0000000 0000000 """Storage paths snapshot."""
DATA_STORAGE_PATHS = {
"count": 3,
"next": None,
"previous": None,
"all": [1, 2, 3, 4, 5],
"results": [
{
"id": 1,
"slug": "work",
"name": "Work Work Work",
"path": "{owner_username}/work/{correspondent}_{created}_{document_type}_{title}",
"match": "",
"matching_algorithm": 6,
"is_insensitive": True,
"document_count": 384,
"owner": 3,
"user_can_change": True,
},
{
"id": 2,
"slug": "banking",
"name": "Banking",
"path": "{owner_username}/banking/{correspondent}_{created}_{document_type}_{title}",
"match": "",
"matching_algorithm": 6,
"is_insensitive": True,
"document_count": 303,
"owner": None,
"user_can_change": True,
},
{
"id": 3,
"slug": "another-test",
"name": "Another Test",
"path": "Test/Path/{doc_pk}",
"match": "",
"matching_algorithm": 0,
"is_insensitive": True,
"document_count": 0,
"owner": None,
"user_can_change": True,
},
{
"id": 4,
"slug": "another-test-2",
"name": "Another Test 2",
"path": "Test/Path/{doc_pk}",
"match": "",
"matching_algorithm": 0,
"is_insensitive": True,
"document_count": 0,
"owner": None,
"user_can_change": True,
},
{
"id": 5,
"slug": "another-test-3",
"name": "Another Test 3",
"path": "Test/Path/{doc_pk}",
"match": "",
"matching_algorithm": 0,
"is_insensitive": True,
"document_count": 0,
"owner": None,
"user_can_change": True,
},
],
}
paperless-api-5.1.0/tests/data/tags.py 0000664 0000000 0000000 00000004236 15053074171 0017655 0 ustar 00root root 0000000 0000000 """Tags snapshot."""
DATA_TAGS = {
"count": 2,
"next": None,
"previous": None,
"all": [
1,
2,
3,
4,
5,
],
"results": [
{
"id": 1,
"slug": "important",
"name": "Important",
"color": "#ff0000",
"text_color": "#00ff00",
"match": "",
"matching_algorithm": 0,
"is_insensitive": True,
"is_inbox_tag": False,
"document_count": 20,
"owner": None,
"user_can_change": True,
},
{
"id": 2,
"slug": "inbox",
"name": "Inbox",
"color": "#ff0000",
"text_color": "#00ff00",
"match": "",
"matching_algorithm": 1,
"is_insensitive": True,
"is_inbox_tag": True,
"document_count": 20,
"owner": None,
"user_can_change": True,
},
{
"id": 3,
"slug": "test-3",
"name": "Test 3",
"color": "#ff0000",
"text_color": "#00ff00",
"match": "",
"matching_algorithm": 2,
"is_insensitive": True,
"is_inbox_tag": False,
"document_count": 20,
"owner": None,
"user_can_change": True,
},
{
"id": 4,
"slug": "test-4",
"name": "Test 4",
"color": "#ff0000",
"text_color": "#00ff00",
"match": "",
"matching_algorithm": 3,
"is_insensitive": True,
"is_inbox_tag": False,
"document_count": 20,
"owner": None,
"user_can_change": True,
},
{
"id": 5,
"slug": "test-5",
"name": "Test 5",
"color": "#ff0000",
"text_color": "#00ff00",
"match": "",
"matching_algorithm": 4,
"is_insensitive": True,
"is_inbox_tag": False,
"document_count": 20,
"owner": None,
"user_can_change": True,
},
],
}
paperless-api-5.1.0/tests/data/tasks.py 0000664 0000000 0000000 00000002321 15053074171 0020035 0 ustar 00root root 0000000 0000000 """Tasks snapshot."""
DATA_TASKS = [
{
"id": 1,
"task_id": "11112222-aaaa-bbbb-cccc-333344445555",
"task_file_name": "a.png",
"date_created": "2023-12-16T13:06:29.107815+00:00",
"date_done": None,
"type": "file",
"status": "STARTED",
"result": None,
"acknowledged": False,
"related_document": None,
},
{
"id": 2,
"task_id": "ffffeeee-9999-8888-7777-ddddccccbbbb",
"task_file_name": "b.png",
"date_created": "2023-12-16T13:06:26.117158+00:00",
"date_done": "2023-12-16T13:06:29.859669+00:00",
"type": "file",
"status": "SUCCESS",
"result": "Success. New document id 1780 created",
"acknowledged": False,
"related_document": "1780",
},
{
"id": 3,
"task_id": "abcdef12-3456-7890-abcd-ef1234567890",
"task_file_name": "c.png",
"date_created": "2023-12-16T13:04:28.175624+00:00",
"date_done": "2023-12-16T13:04:32.318797+00:00",
"type": "file",
"status": "SUCCESS",
"result": "Success. New document id 1779 created",
"acknowledged": False,
"related_document": "1779",
},
]
paperless-api-5.1.0/tests/data/token.py 0000664 0000000 0000000 00000000162 15053074171 0020031 0 ustar 00root root 0000000 0000000 """Token snapshot."""
from tests.const import PAPERLESS_TEST_TOKEN
DATA_TOKEN = {"token": PAPERLESS_TEST_TOKEN}
paperless-api-5.1.0/tests/data/users.py 0000664 0000000 0000000 00000025736 15053074171 0020070 0 ustar 00root root 0000000 0000000 """Users snapshot."""
DATA_USERS = {
"count": 4,
"next": None,
"previous": None,
"all": [1, 2, 3, 4],
"results": [
{
"id": 1,
"username": "admin",
"email": "you@inside.me",
"password": "**********",
"first_name": "",
"last_name": "",
"date_joined": "2022-02-11T22:28:25+00:00",
"is_staff": True,
"is_active": False,
"is_superuser": False,
"groups": [],
"user_permissions": [],
"inherited_permissions": [],
},
{
"id": 2,
"username": "alpha",
"email": "alpha@is-not.beta",
"password": "**********",
"first_name": "Alpha",
"last_name": "Centauri",
"date_joined": "2023-06-27T15:59:01.975496+00:00",
"is_staff": False,
"is_active": True,
"is_superuser": False,
"groups": [1],
"user_permissions": [],
"inherited_permissions": [
"documents.delete_customfieldinstance",
"documents.delete_consumptiontemplate",
"documents.delete_customfield",
"documents.add_uisettings",
"documents.view_uisettings",
"documents.view_tag",
"documents.change_customfield",
"documents.view_sharelink",
"documents.change_note",
"documents.view_correspondent",
"documents.change_customfieldinstance",
"documents.delete_note",
"documents.add_consumptiontemplate",
"documents.add_customfield",
"documents.change_sharelink",
"documents.view_consumptiontemplate",
"documents.view_documenttype",
"documents.change_document",
"documents.view_customfieldinstance",
"documents.add_sharelink",
"documents.view_document",
"documents.delete_uisettings",
"documents.add_savedview",
"documents.view_note",
"documents.view_customfield",
"documents.add_customfieldinstance",
"documents.change_uisettings",
"documents.change_savedview",
"documents.add_document",
"documents.add_note",
"documents.change_consumptiontemplate",
"documents.delete_sharelink",
"documents.delete_savedview",
"documents.view_savedview",
"documents.delete_document",
],
},
{
"id": 3,
"username": "omega",
"email": "omega.weapon@ff8.net",
"password": "**********",
"first_name": "Omega",
"last_name": "Weapon",
"date_joined": "2022-02-14T13:42:54+00:00",
"is_staff": True,
"is_active": True,
"is_superuser": True,
"groups": [1],
"user_permissions": [],
"inherited_permissions": [
"documents.change_paperlesstask",
"documents.delete_customfieldinstance",
"django_celery_results.delete_chordcounter",
"paperless_mail.change_processedmail",
"django_celery_results.view_chordcounter",
"documents.view_storagepath",
"documents.delete_tag",
"sessions.delete_session",
"documents.view_log",
"django_celery_results.change_groupresult",
"documents.add_uisettings",
"authtoken.delete_token",
"admin.add_logentry",
"django_celery_results.add_groupresult",
"guardian.view_userobjectpermission",
"paperless_mail.add_processedmail",
"documents.change_customfieldinstance",
"documents.view_correspondent",
"auth.add_permission",
"admin.view_logentry",
"documents.delete_note",
"documents.add_customfield",
"auth.view_permission",
"documents.add_consumptiontemplate",
"guardian.delete_groupobjectpermission",
"documents.change_sharelink",
"documents.view_consumptiontemplate",
"documents.delete_log",
"guardian.delete_userobjectpermission",
"paperless_mail.delete_mailrule",
"sessions.change_session",
"documents.add_tag",
"documents.view_documenttype",
"auth.view_user",
"auth.add_group",
"guardian.view_groupobjectpermission",
"documents.change_document",
"documents.change_savedviewfilterrule",
"paperless_mail.add_mailrule",
"documents.view_customfieldinstance",
"guardian.add_userobjectpermission",
"documents.add_sharelink",
"auth.change_user",
"documents.view_document",
"django_celery_results.delete_taskresult",
"documents.delete_uisettings",
"documents.add_savedview",
"documents.view_note",
"authtoken.view_token",
"authtoken.change_tokenproxy",
"documents.change_storagepath",
"documents.change_uisettings",
"django_celery_results.add_chordcounter",
"paperless_mail.change_mailrule",
"documents.change_documenttype",
"documents.change_savedview",
"auth.delete_permission",
"documents.add_storagepath",
"django_celery_results.change_chordcounter",
"documents.add_note",
"documents.change_consumptiontemplate",
"documents.delete_savedview",
"guardian.change_userobjectpermission",
"admin.delete_logentry",
"authtoken.add_token",
"documents.view_savedview",
"documents.delete_paperlesstask",
"sessions.view_session",
"auth.delete_group",
"paperless_mail.delete_mailaccount",
"documents.add_savedviewfilterrule",
"authtoken.delete_tokenproxy",
"documents.delete_consumptiontemplate",
"authtoken.view_tokenproxy",
"authtoken.change_token",
"documents.delete_customfield",
"contenttypes.change_contenttype",
"documents.change_log",
"paperless_mail.view_mailrule",
"documents.view_uisettings",
"documents.view_tag",
"documents.change_customfield",
"admin.change_logentry",
"documents.view_sharelink",
"documents.change_note",
"documents.delete_savedviewfilterrule",
"auth.add_user",
"django_celery_results.delete_groupresult",
"documents.change_correspondent",
"documents.add_documenttype",
"django_celery_results.view_groupresult",
"documents.add_paperlesstask",
"contenttypes.add_contenttype",
"auth.view_group",
"guardian.change_groupobjectpermission",
"django_celery_results.change_taskresult",
"documents.change_tag",
"paperless_mail.delete_processedmail",
"paperless_mail.change_mailaccount",
"documents.delete_correspondent",
"paperless_mail.view_processedmail",
"documents.delete_storagepath",
"sessions.add_session",
"paperless_mail.add_mailaccount",
"django_celery_results.view_taskresult",
"documents.view_customfield",
"documents.view_paperlesstask",
"documents.add_customfieldinstance",
"django_celery_results.add_taskresult",
"documents.view_savedviewfilterrule",
"documents.add_log",
"guardian.add_groupobjectpermission",
"auth.delete_user",
"auth.change_permission",
"documents.add_document",
"documents.delete_documenttype",
"documents.delete_sharelink",
"documents.add_correspondent",
"authtoken.add_tokenproxy",
"auth.change_group",
"contenttypes.delete_contenttype",
"contenttypes.view_contenttype",
"paperless_mail.view_mailaccount",
"documents.delete_document",
],
},
{
"id": 4,
"username": "zg_test",
"email": "",
"password": "**********",
"first_name": "",
"last_name": "",
"date_joined": "2023-06-27T15:56:39.754859+00:00",
"is_staff": False,
"is_active": True,
"is_superuser": False,
"groups": [1],
"user_permissions": [],
"inherited_permissions": [
"documents.delete_customfieldinstance",
"documents.delete_consumptiontemplate",
"documents.delete_customfield",
"documents.add_uisettings",
"documents.view_uisettings",
"documents.view_tag",
"documents.change_customfield",
"documents.view_sharelink",
"documents.change_note",
"documents.view_correspondent",
"documents.change_customfieldinstance",
"documents.delete_note",
"documents.add_consumptiontemplate",
"documents.add_customfield",
"documents.change_sharelink",
"documents.view_consumptiontemplate",
"documents.view_documenttype",
"documents.change_document",
"documents.view_customfieldinstance",
"documents.add_sharelink",
"documents.view_document",
"documents.delete_uisettings",
"documents.add_savedview",
"documents.view_note",
"documents.view_customfield",
"documents.add_customfieldinstance",
"documents.change_uisettings",
"documents.change_savedview",
"documents.add_document",
"documents.add_note",
"documents.change_consumptiontemplate",
"documents.delete_sharelink",
"documents.delete_savedview",
"documents.view_savedview",
"documents.delete_document",
],
},
],
}
paperless-api-5.1.0/tests/data/workflow.py 0000664 0000000 0000000 00000011506 15053074171 0020567 0 ustar 00root root 0000000 0000000 """Workflow snapshot."""
# mypy: ignore-errors
DATA_WORKFLOWS = {
"count": 3,
"next": None,
"previous": None,
"all": [1, 2, 3],
"results": [
{
"id": 1,
"name": "Importordner Template",
"order": 1,
"enabled": True,
"triggers": [
{
"id": 1,
"sources": [1],
"type": 1,
"filter_path": None,
"filter_filename": "*.pdf",
"filter_mailrule": None,
"matching_algorithm": 0,
"match": "",
"is_insensitive": None,
"filter_has_tags": [],
"filter_has_correspondent": None,
"filter_has_document_type": None,
}
],
"actions": [
{
"id": 1,
"type": 1,
"assign_title": "Some workflow title",
"assign_tags": [4],
"assign_correspondent": 9,
"assign_document_type": 8,
"assign_storage_path": 2,
"assign_owner": 3,
"assign_view_users": [],
"assign_view_groups": [],
"assign_change_users": [],
"assign_change_groups": [],
"assign_custom_fields": [2],
}
],
},
{
"id": 2,
"name": "API Upload Template",
"order": 2,
"enabled": True,
"triggers": [
{
"id": 2,
"sources": [1, 2],
"type": 1,
"filter_path": "/api/*",
"filter_filename": "*.pdf",
"filter_mailrule": None,
"matching_algorithm": 0,
"match": "",
"is_insensitive": None,
"filter_has_tags": [],
"filter_has_correspondent": None,
"filter_has_document_type": None,
}
],
"actions": [
{
"id": 2,
"type": 1,
"assign_title": "API",
"assign_tags": [4],
"assign_correspondent": 9,
"assign_document_type": 12,
"assign_storage_path": 2,
"assign_owner": 3,
"assign_view_users": [],
"assign_view_groups": [],
"assign_change_users": [],
"assign_change_groups": [],
"assign_custom_fields": [5],
}
],
},
{
"id": 3,
"name": "Email Template",
"order": 3,
"enabled": False,
"triggers": [
{
"id": 3,
"sources": [3],
"type": 1,
"filter_path": "/mail/*",
"filter_filename": "*.eml",
"filter_mailrule": 1,
"matching_algorithm": 0,
"match": "",
"is_insensitive": True,
"filter_has_tags": [],
"filter_has_correspondent": None,
"filter_has_document_type": None,
}
],
"actions": [
{
"id": 3,
"type": 1,
"assign_title": None,
"assign_tags": [],
"assign_correspondent": None,
"assign_document_type": None,
"assign_storage_path": None,
"assign_owner": 2,
"assign_view_users": [3, 7],
"assign_view_groups": [1],
"assign_change_users": [6],
"assign_change_groups": [],
"assign_custom_fields": [],
}
],
},
],
}
DATA_WORKFLOW_ACTIONS = {
"count": 0,
"next": None,
"previous": None,
"all": [],
"results": [],
}
for wf in DATA_WORKFLOWS["results"]:
DATA_WORKFLOW_ACTIONS["count"] += 1
for act in wf["actions"]:
DATA_WORKFLOW_ACTIONS["all"].append(act["id"])
DATA_WORKFLOW_ACTIONS["results"].append(act)
DATA_WORKFLOW_TRIGGERS = {
"count": 0,
"next": None,
"previous": None,
"all": [],
"results": [],
}
for wf in DATA_WORKFLOWS["results"]:
DATA_WORKFLOW_TRIGGERS["count"] += 1
for act in wf["triggers"]:
DATA_WORKFLOW_TRIGGERS["all"].append(act["id"])
DATA_WORKFLOW_TRIGGERS["results"].append(act)
paperless-api-5.1.0/tests/ruff.toml 0000664 0000000 0000000 00000000667 15053074171 0017277 0 ustar 00root root 0000000 0000000 # This extend our general Ruff rules specifically for tests
extend = "../pyproject.toml"
lint.extend-select = [
"PT", # Use @pytest.fixture without parentheses
]
lint.extend-ignore = [
"S101", # As these are tests, the usage of assert could be good practise, no?
"S105", # Yes, we hardcoded passwords. It will be ok this time.
"SLF001", # Tests will access private/protected members.
"TC002", # pytest doesn't like this one.
]
paperless-api-5.1.0/tests/test_common.py 0000664 0000000 0000000 00000051601 15053074171 0020333 0 ustar 00root root 0000000 0000000 """Paperless common tests."""
import re
from dataclasses import dataclass, fields
from datetime import date, datetime
from enum import Enum
from typing import TypedDict
import aiohttp
import pytest
from aioresponses import aioresponses
from pypaperless import Paperless
from pypaperless.const import API_PATH, PaperlessResource
from pypaperless.exceptions import (
BadJsonResponseError,
DraftNotSupportedError,
InitializationError,
JsonResponseWithError,
PaperlessConnectionError,
PaperlessForbiddenError,
PaperlessInactiveOrDeletedError,
PaperlessInvalidTokenError,
)
from pypaperless.models import CustomField, Page
from pypaperless.models.base import HelperBase, PaperlessModel
from pypaperless.models.common import (
CUSTOM_FIELD_TYPE_VALUE_MAP,
CustomFieldDateValue,
CustomFieldIntegerValue,
CustomFieldMonetaryValue,
CustomFieldSelectValue,
CustomFieldType,
MatchingAlgorithmType,
ShareLinkFileVersionType,
StatusType,
TaskStatusType,
WorkflowActionType,
WorkflowTriggerSourceType,
WorkflowTriggerType,
)
from pypaperless.models.mixins import helpers
from pypaperless.models.utils import dict_value_to_object, object_to_dict_value
from tests.const import (
PAPERLESS_TEST_PASSWORD,
PAPERLESS_TEST_TOKEN,
PAPERLESS_TEST_URL,
PAPERLESS_TEST_USER,
)
from .data import DATA_CUSTOM_FIELDS, DATA_PATHS, DATA_TOKEN
# mypy: ignore-errors
class TestPaperless:
"""Paperless common test cases."""
async def test_init(self, resp: aioresponses, api: Paperless) -> None:
"""Test init."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=200,
payload=DATA_PATHS,
)
await api.initialize()
assert api.is_initialized
await api.close()
async def test_context(self, resp: aioresponses, api: Paperless) -> None:
"""Test context."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=200,
payload=DATA_PATHS,
)
async with api:
assert api.is_initialized
async def test_properties(self, api: Paperless) -> None:
"""Test properties."""
# version must be None in this case, as we test against
# an uninitialized Paperless object
assert api.host_version is None
assert api.base_url == PAPERLESS_TEST_URL
async def test_init_error(self, resp: aioresponses, api: Paperless) -> None:
"""Test initialization error."""
# simulate connection due no configuration error
with pytest.raises(PaperlessConnectionError):
await api.initialize()
# http status error
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=401,
body="any html",
)
with pytest.raises(PaperlessInvalidTokenError):
await api.initialize()
# http 401 - inactive or deleted user
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=401,
payload={"detail": "User is inactive"},
)
with pytest.raises(PaperlessInactiveOrDeletedError):
await api.initialize()
# http status forbidden
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=403,
body="any html",
)
with pytest.raises(PaperlessForbiddenError):
await api.initialize()
# http ok, wrong payload
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=200,
body="any html",
)
with pytest.raises(InitializationError):
await api.initialize()
@pytest.mark.parametrize(
"exception_cls",
[
PaperlessConnectionError,
PaperlessInvalidTokenError,
PaperlessInactiveOrDeletedError,
PaperlessForbiddenError,
],
)
async def test_errors_are_backwards_compatible(self, exception_cls: type) -> None:
"""Test, if new errors are backwards compatible."""
assert issubclass(exception_cls, InitializationError)
async def test_jsonresponsewitherror(self) -> None:
"""Test JsonResponseWithError."""
try:
payload = "sample string"
raise JsonResponseWithError(payload) # noqa: TRY301
except JsonResponseWithError as exc:
assert exc.args[0] == "Paperless [error]: sample string" # noqa: PT017
try:
payload = {"failure": "something failed"}
raise JsonResponseWithError(payload) # noqa: TRY301
except JsonResponseWithError as exc:
assert exc.args[0] == "Paperless [failure]: something failed" # noqa: PT017
try:
payload = {"error": ["that", "should", "have", "been", "never", "happened"]}
raise JsonResponseWithError(payload) # noqa: TRY301
except JsonResponseWithError as exc:
assert exc.args[0] == "Paperless [error]: that" # noqa: PT017
try:
payload = [{"some": [[{"weird": {"error": ["occurred"]}}]]}]
raise JsonResponseWithError(payload) # noqa: TRY301
except JsonResponseWithError as exc:
assert exc.args[0] == "Paperless [some -> weird -> error]: occurred" # noqa: PT017
async def test_request(self, resp: aioresponses) -> None:
"""Test generate request."""
# we need to use an unmocked PaperlessSession.request() method
# simply don't initialize Paperless and everything will be fine
api = Paperless(
PAPERLESS_TEST_URL,
PAPERLESS_TEST_TOKEN,
)
# test ordinary 200
resp.get(
PAPERLESS_TEST_URL,
status=200,
)
async with api.request("get", PAPERLESS_TEST_URL) as res:
assert res.status
# last but not least, we test sending a form to test the converter
form_data = {
"none_field": None,
"str_field": "Hello Bytes!",
"bytes_field": b"Hello String!",
"tuple_field": (b"Document Content", "filename.pdf"),
"int_field": 23,
"float_field": 13.37,
"int_list": [1, 1, 2, 3, 5, 8, 13],
"dict_field": {"dict_str_field": "str", "dict_int_field": 2},
}
resp.post(
PAPERLESS_TEST_URL,
status=200,
)
async with api.request("post", PAPERLESS_TEST_URL, form=form_data) as res:
assert res.status
# session is still open
await api.close()
async def test_request_json(self, resp: aioresponses, api: Paperless) -> None:
"""Test requests."""
# test 400 bad request with error payload
resp.get(
f"{PAPERLESS_TEST_URL}/400-json-error-payload",
status=400,
headers={"Content-Type": "application/json"},
payload={"error": "sample message"},
)
with pytest.raises(JsonResponseWithError):
await api.request_json("get", f"{PAPERLESS_TEST_URL}/400-json-error-payload")
# test 200 ok with wrong content type
resp.get(
f"{PAPERLESS_TEST_URL}/200-text-error-payload",
status=200,
headers={"Content-Type": "text/plain"},
body='{"error": "sample message"}',
)
with pytest.raises(BadJsonResponseError):
await api.request_json("get", f"{PAPERLESS_TEST_URL}/200-text-error-payload")
# test 200 ok with correct content type, but no json payload
resp.get(
f"{PAPERLESS_TEST_URL}/200-json-text-body",
status=200,
headers={"Content-Type": "application/json"},
body="test 5 23 42 1337",
)
with pytest.raises(BadJsonResponseError):
await api.request_json("get", f"{PAPERLESS_TEST_URL}/200-json-text-body")
async def test_create_url(self) -> None:
"""Test create url util."""
create_url = Paperless._create_base_url # pylint: disable=protected-access
# test default ssl
url = create_url("hostname")
assert f"{url.host}" == "hostname"
assert int(url.port) == 443
# test enforce http
url = create_url("http://hostname")
assert int(url.port) == 80
# test non-http scheme
url = create_url("ftp://hostname")
assert f"{url.scheme}" == "https"
# should be https even on just setting a port number
url = create_url("hostname:80")
assert f"{url.scheme}" == "https"
# test api/api url
url = create_url("hostname/api/api/")
assert f"{url}" == "https://hostname/api/api"
# test slashes
url = create_url("hostname/api/endpoint///")
assert f"{url}" == "https://hostname/api/endpoint"
async def test_generate_api_token(self, resp: aioresponses, api: Paperless) -> None:
"""Test generate api token."""
# test successful token creation
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH['token']}",
status=200,
payload=DATA_TOKEN,
)
token = await api.generate_api_token(
PAPERLESS_TEST_URL,
PAPERLESS_TEST_USER,
PAPERLESS_TEST_PASSWORD,
)
assert token == PAPERLESS_TEST_TOKEN
# test token creation with wrong json answer
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH['token']}",
status=200,
payload={"blah": "any string"},
)
with pytest.raises(BadJsonResponseError):
token = await api.generate_api_token(
PAPERLESS_TEST_URL,
PAPERLESS_TEST_USER,
PAPERLESS_TEST_PASSWORD,
)
# test error 400
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH['token']}",
status=400,
payload={"non_field_errors": ["Unable to log in."]},
)
with pytest.raises(JsonResponseWithError):
token = await api.generate_api_token(
PAPERLESS_TEST_URL,
PAPERLESS_TEST_USER,
PAPERLESS_TEST_PASSWORD,
)
# general exception
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH['token']}",
exception=ValueError,
)
with pytest.raises(ValueError): # noqa: PT011
token = await api.generate_api_token(
PAPERLESS_TEST_URL,
PAPERLESS_TEST_USER,
PAPERLESS_TEST_PASSWORD,
)
async def test_generate_api_token_with_session(
self, resp: aioresponses, api: Paperless
) -> None:
"""Test generate api token with custom session."""
session = aiohttp.ClientSession()
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH['token']}",
status=200,
payload=DATA_TOKEN,
)
token = await api.generate_api_token(
PAPERLESS_TEST_URL,
PAPERLESS_TEST_USER,
PAPERLESS_TEST_PASSWORD,
session=session,
)
assert token == PAPERLESS_TEST_TOKEN
async def test_types(self) -> None:
"""Test types."""
never_str = "!never_existing_type!"
never_int = 99952342
assert PaperlessResource(never_str) == PaperlessResource.UNKNOWN
assert CustomFieldType(never_str) == CustomFieldType.UNKNOWN
assert MatchingAlgorithmType(never_int) == MatchingAlgorithmType.UNKNOWN
assert ShareLinkFileVersionType(never_str) == ShareLinkFileVersionType.UNKNOWN
assert StatusType(never_str) == StatusType.UNKNOWN
assert TaskStatusType(never_str) == TaskStatusType.UNKNOWN
assert WorkflowActionType(never_int) == WorkflowActionType.UNKNOWN
assert WorkflowTriggerType(never_int) == WorkflowTriggerType.UNKNOWN
assert WorkflowTriggerSourceType(never_int) == WorkflowTriggerSourceType.UNKNOWN
async def test_custom_field_draft_value_wo_cache(self, paperless: Paperless) -> None:
"""Test draft custom field value without cache."""
custom_field = CustomField.create_with_data(
paperless,
data={"id": 1337, "name": "Test", "data_type": CustomFieldType.INTEGER},
fetched=True,
)
field_value = custom_field.draft_value(1337)
for value_type in CUSTOM_FIELD_TYPE_VALUE_MAP.values():
assert not isinstance(field_value, value_type)
async def test_custom_field_draft_value_wslash_cache(
self, resp: aioresponses, paperless: Paperless
) -> None:
"""Test draft custom field value with cache."""
# set custom fields cache
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['custom_fields']}" + r"\?.*$"),
status=200,
payload=DATA_CUSTOM_FIELDS,
)
paperless.cache.custom_fields = await paperless.custom_fields.as_dict()
custom_field = CustomField.create_with_data(
api=paperless,
data=DATA_CUSTOM_FIELDS["results"][5],
fetched=True,
)
field_value = custom_field.draft_value(1337, expected_type=CustomFieldIntegerValue)
assert isinstance(field_value, CustomFieldIntegerValue)
async def test_custom_field_date_value(self) -> None:
"""Test `CustomFieldDateValue`."""
test = CustomFieldDateValue(value="1900-01-02")
assert isinstance(test.value, date)
test = CustomFieldDateValue(value="1900-01-02T03:04:05.133337Z")
assert isinstance(test.value, date)
async def test_custom_field_monetary_value(self) -> None:
"""Test `CustomFieldMonetaryValue`."""
field = CustomFieldMonetaryValue(value="EUR1337.00")
assert field.currency == "EUR"
assert field.amount == 1337
field.amount = 123.45678
assert field.amount == 123.46 # round
field.extra_data = {"default_currency": "USD"}
assert field.value == "EUR123.46"
field.value = "123.45" # no currency
assert field.currency == "USD"
field.extra_data = {}
assert field.currency == ""
field.currency = "EUR"
assert field.value == "EUR123.45"
field.currency = ""
assert field.value == "123.45"
field.value = None
assert field.amount is None
async def test_custom_field_select_value(self) -> None:
"""Test custom field value types."""
test = CustomFieldSelectValue(
value="id2",
extra_data={
"select_options": [
{"id": "id1", "label": "label1"},
{"id": "id2", "label": "label2"},
]
},
)
assert isinstance(test.labels, list)
assert test.label == "label2"
# test fail
test.extra_data = None
assert test.label is None
async def test_dataclass_conversion(self) -> None: # pylint: disable=too-many-statements
"""Test dataclass utils."""
class SomeStatus(Enum):
"""Test enum."""
ACTIVE = 1
INACTIVE = 2
UNKNOWN = -1
@classmethod
def _missing_(cls: "SomeStatus", *_: object) -> "SomeStatus":
"""Set default."""
return cls.UNKNOWN
class SomeNestedExtraData(TypedDict):
"""Test nested TypedDict."""
ustr: str | None
uany: int | str | bool | None
class SomeExtraData(TypedDict):
"""Test TypedDict."""
a_str: str
a_dict: dict[str, str]
a_list: list[str]
a_typeddict: SomeNestedExtraData
@dataclass
class SomeFriend:
"""Test class."""
name: str
age: int
@classmethod
def from_dict(cls, data: dict) -> "SomeFriend":
"""Test from_dict stuff."""
return cls(name=str(data.get("name")), age=int(data.get("age")))
@dataclass
class SomePerson:
"""Test class."""
name: str
age: int
height: float
height2: float
birth: date
last_login: datetime
friends: list[SomeFriend] | None
deleted: datetime | None
is_deleted: bool
status: SomeStatus
file: bytes
meta: dict[str, str]
extra_data: SomeExtraData
raw_data = {
"name": "Lee Tobi, Sajangnim",
"age": 38,
"height": 1.76,
"height2": 2,
"birth": "1986-05-23",
"last_login": "2023-08-08T06:06:35.495972Z",
"is_deleted": False,
"friends": [
{
"name": "Erika",
"age": "50", # this should be int, check "back conversion" at bottom
},
{
"name": "Reinhard",
"age": 40,
},
],
"status": 1,
"file": b"5-23-42-666-0815-1337",
"meta": {"hairs": "blonde", "eyes": "blue", "loves": "Python"},
"extra_data": {
"a_str": "test",
"a_dict": {
"key1": "val1",
"key2": "val2",
},
"a_list": ["a", "b", "c"],
"a_typeddict": {"ustr": "hello", "uany": 1},
},
}
data = {
field.name: dict_value_to_object(
f"_Person.{__name__}.{field.name}",
raw_data.get(field.name),
field.type,
field.default,
)
for field in fields(SomePerson)
}
res = SomePerson(**data)
assert isinstance(res.name, str)
assert isinstance(res.age, int)
assert isinstance(res.height, float)
assert isinstance(res.height2, float)
assert isinstance(res.birth, date)
assert isinstance(res.last_login, datetime)
assert isinstance(res.friends, list)
assert isinstance(res.friends[0], SomeFriend)
assert isinstance(res.friends[0].age, int)
assert isinstance(res.friends[1].age, int)
assert res.deleted is None
assert res.is_deleted is False
assert isinstance(res.status, SomeStatus)
assert isinstance(res.file, bytes)
assert isinstance(res.extra_data, dict)
assert isinstance(res.extra_data["a_typeddict"], dict)
# back conversion
back = {field.name: object_to_dict_value(getattr(res, field.name)) for field in fields(res)}
assert isinstance(back["friends"][0]["age"], int) # was str in the source dict
assert isinstance(back["meta"], dict)
assert isinstance(back["extra_data"], dict)
assert isinstance(back["extra_data"]["a_list"], list)
async def test_pages_object(self, api: Paperless) -> None:
"""Test pages."""
@dataclass(init=False)
class TestResource(PaperlessModel):
"""Test Resource."""
id: int | None = None
data = {
"count": 0,
"current_page": 1,
"page_size": 25,
"next": "any.url",
"previous": None,
"all": [],
"results": [],
}
for i in range(1, 101):
data["count"] += 1
data["all"].append(i)
data["results"].append({"id": i})
page = Page.create_with_data(api, data=data, fetched=True)
page._resource_cls = TestResource # pylint: disable=protected-access
assert isinstance(page, Page)
assert page.current_count == 100
for item in page:
assert isinstance(item, TestResource)
# check first page
assert not page.has_previous_page
assert page.has_next_page
assert not page.is_last_page
assert page.last_page == 4
assert page.next_page == 2
assert page.previous_page is None
# check inner page
page.previous = "any.url"
page.current_page = 3
assert page.previous_page is not None
assert page.next_page is not None
assert not page.is_last_page
# check last page
page.next = None
page.current_page = 4
assert page.next_page is None
assert page.is_last_page
async def test_draft_exc(self, api: Paperless) -> None:
"""Test draft not supported."""
@dataclass(init=False)
class TestResource(PaperlessModel):
"""Test Resource."""
class TestHelper(HelperBase, helpers.DraftableMixin):
"""Test Helper."""
_api_path = "any.url"
_resource = "test"
# draft_cls - we "forgot" to set a draft class, which will raise
_resource_cls = TestResource
helper = TestHelper(api)
with pytest.raises(DraftNotSupportedError):
# ... there it is
helper.draft()
paperless-api-5.1.0/tests/test_models_matrix.py 0000664 0000000 0000000 00000035140 15053074171 0021712 0 ustar 00root root 0000000 0000000 """Paperless basic tests."""
import re
from typing import Any
import aiohttp
import pytest
from aioresponses import CallbackResult, aioresponses
from pypaperless import Paperless
from pypaperless.const import API_PATH
from pypaperless.exceptions import DraftFieldRequiredError
from pypaperless.models import Page
from pypaperless.models.common import PermissionTableType
from . import (
CORRESPONDENT_MAP,
CUSTOM_FIELD_MAP,
DOCUMENT_MAP,
DOCUMENT_TYPE_MAP,
GROUP_MAP,
MAIL_ACCOUNT_MAP,
MAIL_RULE_MAP,
SAVED_VIEW_MAP,
SHARE_LINK_MAP,
STORAGE_PATH_MAP,
TAG_MAP,
USER_MAP,
WORKFLOW_MAP,
ResourceTestMapping,
)
from .const import PAPERLESS_TEST_URL
from .data import DATA_OBJECT_PERMISSIONS
# mypy: ignore-errors
@pytest.mark.parametrize(
"mapping",
[
DOCUMENT_MAP,
DOCUMENT_TYPE_MAP,
CORRESPONDENT_MAP,
CUSTOM_FIELD_MAP,
GROUP_MAP,
MAIL_ACCOUNT_MAP,
MAIL_RULE_MAP,
SAVED_VIEW_MAP,
SHARE_LINK_MAP,
STORAGE_PATH_MAP,
TAG_MAP,
USER_MAP,
WORKFLOW_MAP,
],
scope="class",
)
# test models/classifiers.py
# test models/custom_fields.py
# test models/mails.py
# test models/permissions.py
# test models/saved_views.py
# test models/share_links.py
class TestReadOnly:
"""Read only resources test cases."""
async def test_pages(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test pages."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
page = await anext(aiter(getattr(paperless, mapping.resource).pages(1)))
assert isinstance(page, Page)
assert isinstance(page.items, list)
for item in page.items:
assert isinstance(item, mapping.model_cls)
async def test_as_dict(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test as_dict."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
items = await getattr(paperless, mapping.resource).as_dict()
for pk, obj in items.items():
assert isinstance(pk, int)
assert isinstance(obj, mapping.model_cls)
async def test_as_list(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test as_dict."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
items = await getattr(paperless, mapping.resource).as_list()
for obj in items:
assert isinstance(obj, mapping.model_cls)
async def test_iter(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test iter."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
async for item in getattr(paperless, mapping.resource):
assert isinstance(item, mapping.model_cls)
async def test_all(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test all."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
items = await getattr(paperless, mapping.resource).all()
assert isinstance(items, list)
for item in items:
assert isinstance(item, int)
async def test_call(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload=mapping.data["results"][0],
)
item = await getattr(paperless, mapping.resource)(1)
assert item
assert isinstance(item, mapping.model_cls)
# must raise as 1337 doesn't exist
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1337),
status=404,
)
with pytest.raises(aiohttp.ClientResponseError):
await getattr(paperless, mapping.resource)(1337)
@pytest.mark.parametrize(
"mapping",
[
CORRESPONDENT_MAP,
CUSTOM_FIELD_MAP,
DOCUMENT_TYPE_MAP,
SHARE_LINK_MAP,
STORAGE_PATH_MAP,
TAG_MAP,
],
scope="class",
)
# test models/classifiers.py
# test models/custom_fields.py
# test models/share_links.py
class TestReadWrite:
"""R/W models test cases."""
async def test_pages(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test pages."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
page = await anext(aiter(getattr(paperless, mapping.resource).pages(1)))
assert isinstance(page, Page)
assert isinstance(page.items, list)
for item in page.items:
assert isinstance(item, mapping.model_cls)
async def test_iter(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test iter."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
async for item in getattr(paperless, mapping.resource):
assert isinstance(item, mapping.model_cls)
async def test_all(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test all."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
items = await getattr(paperless, mapping.resource).all()
assert isinstance(items, list)
for item in items:
assert isinstance(item, int)
async def test_reduce(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test iter with reduce."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=mapping.data,
)
async with getattr(paperless, mapping.resource).reduce(
any_filter_param="1",
any_filter_list__in=["1", "2"],
any_filter_no_list__in="1",
) as q:
async for item in q:
assert isinstance(item, mapping.model_cls)
async def test_call(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload=mapping.data["results"][0],
)
item = await getattr(paperless, mapping.resource)(1)
assert item
assert isinstance(item, mapping.model_cls)
# must raise as 1337 doesn't exist
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1337),
status=404,
)
with pytest.raises(aiohttp.ClientResponseError):
await getattr(paperless, mapping.resource)(1337)
async def test_create(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test create."""
draft = getattr(paperless, mapping.resource).draft(**mapping.draft_defaults)
assert isinstance(draft, mapping.draft_cls)
# test empty draft fields
if mapping.model_cls not in (
SHARE_LINK_MAP.model_cls,
CUSTOM_FIELD_MAP.model_cls,
):
backup = draft.name
draft.name = None
with pytest.raises(DraftFieldRequiredError):
await draft.save()
draft.name = backup
# actually call the create endpoint
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}",
status=200,
payload={
"id": len(mapping.data["results"]),
**draft._serialize(), # pylint: disable=protected-access
},
)
new_pk = await draft.save()
assert new_pk >= 1
async def test_udpate(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test update."""
update_field = "name"
update_value = "Name Updated"
if mapping.model_cls is SHARE_LINK_MAP.model_cls:
update_field = "document"
update_value = 2
# go on
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload=mapping.data["results"][0],
)
to_update = await getattr(paperless, mapping.resource)(1)
setattr(to_update, update_field, update_value)
# actually call the update endpoint
resp.patch(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload={
**to_update._data, # pylint: disable=protected-access
update_field: update_value,
},
)
await to_update.update()
assert getattr(to_update, update_field) == update_value
# no updates
assert not await to_update.update()
# force update
setattr(to_update, update_field, update_value)
resp.put(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload={
**to_update._data, # pylint: disable=protected-access
update_field: update_value,
},
)
await to_update.update(only_changed=False)
assert getattr(to_update, update_field) == update_value
async def test_delete(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test delete."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload=mapping.data["results"][0],
)
to_delete = await getattr(paperless, mapping.resource)(1)
resp.delete(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=204, # Paperless-ngx responds with 204 on deletion
)
assert await to_delete.delete()
# test deletion failed
resp.delete(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=404, # we send another status code
)
assert not await to_delete.delete()
@pytest.mark.parametrize(
"mapping",
[
CORRESPONDENT_MAP,
DOCUMENT_MAP,
DOCUMENT_TYPE_MAP,
STORAGE_PATH_MAP,
TAG_MAP,
],
scope="class",
)
# test models/classifiers.py
class TestSecurableMixin:
"""SecurableMixin test cases."""
async def test_permissions(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test permissions."""
getattr(paperless, mapping.resource).request_permissions = True
assert getattr(paperless, mapping.resource).request_permissions
# request single object
resp.get(
re.compile(
r"^"
+ f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1)
+ r"\?.*$"
),
status=200,
payload={
**mapping.data["results"][0],
"permissions": DATA_OBJECT_PERMISSIONS,
},
)
item = await getattr(paperless, mapping.resource)(1)
assert item.has_permissions
assert isinstance(item.permissions, PermissionTableType)
# request by iterator
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload={
**mapping.data,
"results": [
{**item, "permissions": DATA_OBJECT_PERMISSIONS}
for item in mapping.data["results"]
],
},
)
async for item in getattr(paperless, mapping.resource):
assert isinstance(item, mapping.model_cls)
assert item.has_permissions
assert isinstance(item.permissions, PermissionTableType)
async def test_permission_change(
self, resp: aioresponses, paperless: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test permission changes."""
getattr(paperless, mapping.resource).request_permissions = True
assert getattr(paperless, mapping.resource).request_permissions
resp.get(
re.compile(
r"^"
+ f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1)
+ r"\?.*$"
),
status=200,
payload={
**mapping.data["results"][0],
"permissions": DATA_OBJECT_PERMISSIONS,
},
)
item = await getattr(paperless, mapping.resource)(1)
item.permissions.view.users.append(23)
def _lookup_set_permissions( # pylint: disable=unused-argument
url: str,
json: dict[str, Any],
**kwargs: Any, # noqa: ARG001
) -> CallbackResult:
assert url
assert "set_permissions" in json
return CallbackResult(
status=200,
payload=item._data, # pylint: disable=protected-access
)
resp.patch(
re.compile(
r"^"
+ f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1)
+ r"\?.*$"
),
callback=_lookup_set_permissions,
)
await item.update()
paperless-api-5.1.0/tests/test_models_specific.py 0000664 0000000 0000000 00000050705 15053074171 0022177 0 ustar 00root root 0000000 0000000 """Paperless basic tests."""
import datetime
import re
import aiohttp
import pytest
from aioresponses import aioresponses
from pypaperless import Paperless
from pypaperless.const import API_PATH
from pypaperless.exceptions import (
AsnRequestError,
DraftFieldRequiredError,
PrimaryKeyRequiredError,
TaskNotFoundError,
)
from pypaperless.models import (
Config,
CustomField,
Document,
DocumentDraft,
DocumentMeta,
DocumentNote,
DocumentNoteDraft,
Status,
Task,
)
from pypaperless.models.common import (
CUSTOM_FIELD_TYPE_VALUE_MAP,
CustomFieldBooleanValue,
CustomFieldDocumentLinkValue,
CustomFieldValue,
DocumentMetadataType,
DocumentSearchHitType,
RetrieveFileMode,
StatisticDocumentFileTypeCount,
StatusDatabaseType,
StatusStorageType,
StatusTasksType,
)
from pypaperless.models.documents import (
DocumentCustomFieldList,
DocumentSuggestions,
DownloadedDocument,
)
from pypaperless.models.workflows import WorkflowActionHelper, WorkflowTriggerHelper
from . import DOCUMENT_MAP
from .const import PAPERLESS_TEST_URL
from .data import (
DATA_CONFIG,
DATA_CUSTOM_FIELDS,
DATA_DOCUMENT_METADATA,
DATA_DOCUMENT_NOTES,
DATA_DOCUMENT_SUGGESTIONS,
DATA_DOCUMENTS,
DATA_DOCUMENTS_SEARCH,
DATA_REMOTE_VERSION,
DATA_STATISTICS,
DATA_STATUS,
DATA_TASKS,
)
# mypy: ignore-errors
# test models/config.py
class TestModelConfig:
"""Config test cases."""
async def test_call(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['config_single']}".format(pk=1),
status=200,
payload=DATA_CONFIG[0],
)
item = await paperless.config(1)
assert item
assert isinstance(item, Config)
# must raise as 1337 doesn't exist
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['config_single']}".format(pk=1337),
status=404,
)
with pytest.raises(aiohttp.ClientResponseError):
await paperless.config(1337)
# test models/documents.py
class TestModelDocuments:
"""Documents test cases."""
async def test_lazy(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test laziness."""
document = Document(paperless, data={"id": 1})
assert not document.is_fetched
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
await document.load()
assert document.is_fetched
async def test_create(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test create."""
defaults = DOCUMENT_MAP.draft_defaults or {}
draft = paperless.documents.draft(**defaults)
assert isinstance(draft, DocumentDraft)
backup = draft.document
draft.document = None
with pytest.raises(DraftFieldRequiredError):
await draft.save()
draft.document = backup
# actually call the create endpoint
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_post']}",
status=200,
payload="11112222-3333-4444-5555-666677778888",
)
await draft.save()
async def test_create_date_property(self, paperless: Paperless) -> None:
"""Test create_date property - well, lol."""
document = Document.create_with_data(
paperless, data={**DATA_DOCUMENTS["results"][0]}, fetched=True
)
assert document.created_date == document.created
async def test_udpate(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test update."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
to_update = await paperless.documents(1)
new_title = f"{to_update.title} Updated"
to_update.title = new_title
# actually call the update endpoint
resp.patch(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload={
**to_update._data, # pylint: disable=protected-access
"title": new_title,
},
)
await to_update.update()
assert to_update.title == new_title
async def test_delete(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test delete."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
to_delete = await paperless.documents(1)
resp.delete(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=204, # Paperless-ngx responds with 204 on deletion
)
assert await to_delete.delete()
# test deletion failed
resp.delete(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=404, # we send another status code
)
assert not await to_delete.delete()
async def test_meta(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test meta."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
document = await paperless.documents(1)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_meta']}".format(pk=1),
status=200,
payload=DATA_DOCUMENT_METADATA,
)
meta = await document.get_metadata()
assert isinstance(meta, DocumentMeta)
assert isinstance(meta.original_metadata, list)
for item in meta.original_metadata:
assert isinstance(item, DocumentMetadataType)
assert isinstance(meta.archive_metadata, list)
for item in meta.archive_metadata:
assert isinstance(item, DocumentMetadataType)
async def test_files(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test files."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
document = await paperless.documents(1)
resp.get(
re.compile(
r"^"
+ f"{PAPERLESS_TEST_URL}{API_PATH['documents_download']}".format(pk=1)
+ r"\?.*$"
),
status=200,
headers={
"Content-Type": "application/pdf",
"Content-Disposition": "attachment;filename=any_filename.pdf",
},
body=b"Binary data: download",
)
download = await document.get_download()
assert isinstance(download, DownloadedDocument)
assert download.mode == RetrieveFileMode.DOWNLOAD
resp.get(
re.compile(
r"^"
+ f"{PAPERLESS_TEST_URL}{API_PATH['documents_preview']}".format(pk=1)
+ r"\?.*$"
),
status=200,
headers={
"Content-Type": "application/pdf",
},
body=b"Binary data: preview",
)
preview = await document.get_preview()
assert isinstance(preview, DownloadedDocument)
assert preview.mode == RetrieveFileMode.PREVIEW
resp.get(
re.compile(
r"^"
+ f"{PAPERLESS_TEST_URL}{API_PATH['documents_thumbnail']}".format(pk=1)
+ r"\?.*$"
),
status=200,
body=b"Binary data: thumbnail",
)
thumbnail = await document.get_thumbnail()
assert isinstance(thumbnail, DownloadedDocument)
assert thumbnail.mode == RetrieveFileMode.THUMBNAIL
async def test_suggestions(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test suggestions."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
document = await paperless.documents(1)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_suggestions']}".format(pk=1),
status=200,
payload=DATA_DOCUMENT_SUGGESTIONS,
)
suggestions = await document.get_suggestions()
assert isinstance(suggestions, DocumentSuggestions)
async def test_get_next_an(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test get next asn."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_next_asn']}",
status=200,
payload=1337,
)
asn = await paperless.documents.get_next_asn()
assert isinstance(asn, int)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_next_asn']}",
status=500,
)
with pytest.raises(AsnRequestError):
await paperless.documents.get_next_asn()
async def test_searching(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test searching."""
# search
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['documents']}" + r"\?.*query.*$"),
status=200,
payload=DATA_DOCUMENTS_SEARCH,
)
async for item in paperless.documents.search("1337"):
assert isinstance(item, Document)
assert item.has_search_hit
assert isinstance(item.search_hit, DocumentSearchHitType)
# more_like
resp.get(
re.compile(
r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['documents']}" + r"\?.*more_like_id.*$"
),
status=200,
payload=DATA_DOCUMENTS_SEARCH,
)
async for item in paperless.documents.more_like(1337):
assert isinstance(item, Document)
assert item.has_search_hit
assert isinstance(item.search_hit, DocumentSearchHitType)
async def test_note_call(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
item = await paperless.documents(1)
assert isinstance(item, Document)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_notes']}".format(pk=1),
status=200,
payload=DATA_DOCUMENT_NOTES,
)
results = await item.notes()
assert isinstance(results, list)
assert len(results) > 0
for note in results:
assert isinstance(note, DocumentNote)
assert isinstance(note.created, datetime.datetime)
with pytest.raises(PrimaryKeyRequiredError):
item = await paperless.documents.notes()
async def test_note_create(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test create."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
item = await paperless.documents(1)
draft = item.notes.draft(note="Test note.")
assert isinstance(draft, DocumentNoteDraft)
backup = draft.note
draft.note = None
with pytest.raises(DraftFieldRequiredError):
await draft.save()
draft.note = backup
# actually call the create endpoint
resp.post(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_notes']}".format(pk=1),
status=200,
payload=DATA_DOCUMENT_NOTES,
)
result = await draft.save()
assert isinstance(result, tuple)
async def test_note_delete(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test delete."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=DATA_DOCUMENTS["results"][0],
)
item = await paperless.documents(1)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_notes']}".format(pk=1),
status=200,
payload=DATA_DOCUMENT_NOTES,
)
results = await item.notes()
resp.delete(
re.compile(
r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['documents_notes']}".format(pk=1) + r"\?.*$"
),
status=204, # Paperless-ngx responds with 204 on deletion
)
deletion = await results.pop().delete()
assert deletion
async def test_custom_field_list_wo_cache(
self, resp: aioresponses, paperless: Paperless
) -> None:
"""Test custom field list without cache."""
# request document
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=2),
status=200,
payload=DATA_DOCUMENTS["results"][1],
)
item = await paperless.documents(2)
assert isinstance(item.custom_fields, DocumentCustomFieldList)
# every item MUST NOT be a derived CustomFieldValue instance
for field in item.custom_fields:
for value_type in CUSTOM_FIELD_TYPE_VALUE_MAP.values():
assert not isinstance(field, value_type)
assert isinstance(field, CustomFieldValue)
async def test_custom_field_list_wslash_cache(
self, resp: aioresponses, paperless: Paperless
) -> None:
"""Test custom fields list with cache."""
# set custom fields cache
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['custom_fields']}" + r"\?.*$"),
status=200,
payload=DATA_CUSTOM_FIELDS,
)
paperless.cache.custom_fields = await paperless.custom_fields.as_dict()
# request document
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=2),
status=200,
payload=DATA_DOCUMENTS["results"][1],
)
item = await paperless.documents(2)
assert isinstance(item.custom_fields, DocumentCustomFieldList)
# every item may be a derived class or not
for field in item.custom_fields:
assert isinstance(field, CustomFieldValue)
# test if custom field is in document custom field values
test_cf = CustomField.create_with_data(
api=paperless,
data=DATA_CUSTOM_FIELDS["results"][0],
fetched=True,
)
assert test_cf in item.custom_fields
assert isinstance(item.custom_fields.get(test_cf), CustomFieldValue)
assert item.custom_fields.default(test_cf) is not None
assert item.custom_fields.default(-1337) is None
# test typed getters
assert isinstance(
item.custom_fields.get(test_cf, CustomFieldDocumentLinkValue),
CustomFieldDocumentLinkValue,
)
assert isinstance(
item.custom_fields.default(test_cf, CustomFieldDocumentLinkValue),
CustomFieldDocumentLinkValue,
)
with pytest.raises(TypeError):
item.custom_fields.get(test_cf, CustomFieldBooleanValue)
with pytest.raises(TypeError):
item.custom_fields.default(test_cf, CustomFieldBooleanValue)
# test remove field value
item.custom_fields -= test_cf
assert test_cf not in item.custom_fields
# test add field value
item.custom_fields += test_cf.draft_value(1337)
assert test_cf in item.custom_fields
# test models/remote_version.py
class TestModelVersion:
"""Version test cases."""
async def test_call(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['remote_version']}",
status=200,
payload=DATA_REMOTE_VERSION,
)
remote_version = await paperless.remote_version()
assert remote_version
assert isinstance(remote_version.version, str)
assert isinstance(remote_version.update_available, bool)
# test models/statistics.py
class TestModelStatistics:
"""Statistics test cases."""
async def test_call(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['statistics']}",
status=200,
payload=DATA_STATISTICS,
)
stats = await paperless.statistics()
assert stats
assert isinstance(stats.character_count, int)
assert isinstance(stats.document_file_type_counts, list)
for item in stats.document_file_type_counts:
assert isinstance(item, StatisticDocumentFileTypeCount)
# test models/status.py
class TestModelStatus:
"""Status test cases."""
async def test_call(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['status']}",
status=200,
payload=DATA_STATUS,
)
status = await paperless.status()
assert status
assert isinstance(status, Status)
assert isinstance(status.storage, StatusStorageType)
assert isinstance(status.database, StatusDatabaseType)
assert isinstance(status.tasks, StatusTasksType)
async def test_has_errors(self, paperless: Paperless) -> None:
"""Test has errors."""
data = {
"database": {
"status": "OK",
},
"tasks": {
"redis_status": "OK",
"celery_status": "OK",
"classifier_status": "OK",
},
}
# everything fine as we initialized Status with OK values only
status = Status.create_with_data(paperless, data=data, fetched=True)
assert status.has_errors is False
# lets set something to ERROR
data["database"]["status"] = "ERROR"
status = Status.create_with_data(paperless, data=data, fetched=True)
assert status.has_errors is True
# assume any status value is None; None values are treated as no errors
del data["database"]["status"]
status = Status.create_with_data(paperless, data=data, fetched=True)
assert status.has_errors is False
# test models/tasks.py
class TestModelTasks:
"""Tasks test cases."""
async def test_iter(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test iter."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['tasks']}" + r".*$"),
status=200,
payload=DATA_TASKS,
)
async for item in paperless.tasks:
assert isinstance(item, Task)
async def test_call(self, resp: aioresponses, paperless: Paperless) -> None:
"""Test call."""
# by pk
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['tasks_single']}".format(pk=1),
status=200,
payload=DATA_TASKS[0],
)
item = await paperless.tasks(1)
assert item
assert isinstance(item, Task)
# by uuid
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['tasks']}" + r"\?task_id.*$"),
status=200,
payload=DATA_TASKS,
)
item = await paperless.tasks("dummy-found")
assert item
assert isinstance(item, Task)
# must raise as pk doesn't exist
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['tasks_single']}".format(pk=1337),
status=404,
)
with pytest.raises(aiohttp.ClientResponseError):
await paperless.tasks(1337)
# must raise as task_id doesn't exist
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['tasks']}" + r"\?task_id.*$"),
status=200,
payload=[],
)
with pytest.raises(TaskNotFoundError):
await paperless.tasks("dummy-not-found")
# test models/workflows.py
class TestModelWorkflows:
"""Tasks test cases."""
async def test_helpers(self, paperless: Paperless) -> None:
"""Test helpers."""
assert isinstance(paperless.workflows.actions, WorkflowActionHelper)
assert isinstance(paperless.workflows.triggers, WorkflowTriggerHelper)
paperless-api-5.1.0/uv.lock 0000664 0000000 0000000 00000314326 15053074171 0015602 0 ustar 00root root 0000000 0000000 version = 1
revision = 2
requires-python = "==3.13.*"
[[package]]
name = "aiohappyeyeballs"
version = "2.6.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
]
[[package]]
name = "aiohttp"
version = "3.12.15"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohappyeyeballs" },
{ name = "aiosignal" },
{ name = "attrs" },
{ name = "frozenlist" },
{ name = "multidict" },
{ name = "propcache" },
{ name = "yarl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f2/33/918091abcf102e39d15aba2476ad9e7bd35ddb190dcdd43a854000d3da0d/aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315", size = 696741, upload-time = "2025-07-29T05:51:19.021Z" },
{ url = "https://files.pythonhosted.org/packages/b5/2a/7495a81e39a998e400f3ecdd44a62107254803d1681d9189be5c2e4530cd/aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd", size = 474407, upload-time = "2025-07-29T05:51:21.165Z" },
{ url = "https://files.pythonhosted.org/packages/49/fc/a9576ab4be2dcbd0f73ee8675d16c707cfc12d5ee80ccf4015ba543480c9/aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4", size = 466703, upload-time = "2025-07-29T05:51:22.948Z" },
{ url = "https://files.pythonhosted.org/packages/09/2f/d4bcc8448cf536b2b54eed48f19682031ad182faa3a3fee54ebe5b156387/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7", size = 1705532, upload-time = "2025-07-29T05:51:25.211Z" },
{ url = "https://files.pythonhosted.org/packages/f1/f3/59406396083f8b489261e3c011aa8aee9df360a96ac8fa5c2e7e1b8f0466/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d", size = 1686794, upload-time = "2025-07-29T05:51:27.145Z" },
{ url = "https://files.pythonhosted.org/packages/dc/71/164d194993a8d114ee5656c3b7ae9c12ceee7040d076bf7b32fb98a8c5c6/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b", size = 1738865, upload-time = "2025-07-29T05:51:29.366Z" },
{ url = "https://files.pythonhosted.org/packages/1c/00/d198461b699188a93ead39cb458554d9f0f69879b95078dce416d3209b54/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d", size = 1788238, upload-time = "2025-07-29T05:51:31.285Z" },
{ url = "https://files.pythonhosted.org/packages/85/b8/9e7175e1fa0ac8e56baa83bf3c214823ce250d0028955dfb23f43d5e61fd/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d", size = 1710566, upload-time = "2025-07-29T05:51:33.219Z" },
{ url = "https://files.pythonhosted.org/packages/59/e4/16a8eac9df39b48ae102ec030fa9f726d3570732e46ba0c592aeeb507b93/aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645", size = 1624270, upload-time = "2025-07-29T05:51:35.195Z" },
{ url = "https://files.pythonhosted.org/packages/1f/f8/cd84dee7b6ace0740908fd0af170f9fab50c2a41ccbc3806aabcb1050141/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461", size = 1677294, upload-time = "2025-07-29T05:51:37.215Z" },
{ url = "https://files.pythonhosted.org/packages/ce/42/d0f1f85e50d401eccd12bf85c46ba84f947a84839c8a1c2c5f6e8ab1eb50/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9", size = 1708958, upload-time = "2025-07-29T05:51:39.328Z" },
{ url = "https://files.pythonhosted.org/packages/d5/6b/f6fa6c5790fb602538483aa5a1b86fcbad66244997e5230d88f9412ef24c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d", size = 1651553, upload-time = "2025-07-29T05:51:41.356Z" },
{ url = "https://files.pythonhosted.org/packages/04/36/a6d36ad545fa12e61d11d1932eef273928b0495e6a576eb2af04297fdd3c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693", size = 1727688, upload-time = "2025-07-29T05:51:43.452Z" },
{ url = "https://files.pythonhosted.org/packages/aa/c8/f195e5e06608a97a4e52c5d41c7927301bf757a8e8bb5bbf8cef6c314961/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64", size = 1761157, upload-time = "2025-07-29T05:51:45.643Z" },
{ url = "https://files.pythonhosted.org/packages/05/6a/ea199e61b67f25ba688d3ce93f63b49b0a4e3b3d380f03971b4646412fc6/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51", size = 1710050, upload-time = "2025-07-29T05:51:48.203Z" },
{ url = "https://files.pythonhosted.org/packages/b4/2e/ffeb7f6256b33635c29dbed29a22a723ff2dd7401fff42ea60cf2060abfb/aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0", size = 422647, upload-time = "2025-07-29T05:51:50.718Z" },
{ url = "https://files.pythonhosted.org/packages/1b/8e/78ee35774201f38d5e1ba079c9958f7629b1fd079459aea9467441dbfbf5/aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84", size = 449067, upload-time = "2025-07-29T05:51:52.549Z" },
]
[[package]]
name = "aioresponses"
version = "0.7.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
{ name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/de/03/532bbc645bdebcf3b6af3b25d46655259d66ce69abba7720b71ebfabbade/aioresponses-0.7.8.tar.gz", hash = "sha256:b861cdfe5dc58f3b8afac7b0a6973d5d7b2cb608dd0f6253d16b8ee8eaf6df11", size = 40253, upload-time = "2025-01-19T18:14:03.222Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/12/b7/584157e43c98aa89810bc2f7099e7e01c728ecf905a66cf705106009228f/aioresponses-0.7.8-py2.py3-none-any.whl", hash = "sha256:b73bd4400d978855e55004b23a3a84cb0f018183bcf066a85ad392800b5b9a94", size = 12518, upload-time = "2025-01-19T18:13:59.633Z" },
]
[[package]]
name = "aiosignal"
version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "frozenlist" },
]
sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
]
[[package]]
name = "astroid"
version = "3.3.11"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/18/74/dfb75f9ccd592bbedb175d4a32fc643cf569d7c218508bfbd6ea7ef9c091/astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce", size = 400439, upload-time = "2025-07-13T18:04:23.177Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/af/0f/3b8fdc946b4d9cc8cc1e8af42c4e409468c84441b933d037e101b3d72d86/astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec", size = 275612, upload-time = "2025-07-13T18:04:21.07Z" },
]
[[package]]
name = "attrs"
version = "25.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
]
[[package]]
name = "cfgv"
version = "3.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" },
]
[[package]]
name = "codespell"
version = "2.4.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/15/e0/709453393c0ea77d007d907dd436b3ee262e28b30995ea1aa36c6ffbccaf/codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5", size = 344740, upload-time = "2025-01-28T18:52:39.411Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/01/b394922252051e97aab231d416c86da3d8a6d781eeadcdca1082867de64e/codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425", size = 344501, upload-time = "2025-01-28T18:52:37.057Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "covdefaults"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage" },
]
sdist = { url = "https://files.pythonhosted.org/packages/44/ee/9a6f2611f72e4c5657ae5542a510cf4164d2c673687c0ea73bb1cbd85b4d/covdefaults-2.3.0.tar.gz", hash = "sha256:4e99f679f12d792bc62e5510fa3eb59546ed47bd569e36e4fddc4081c9c3ebf7", size = 4835, upload-time = "2023-03-05T16:43:34.779Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/4c/823bc951445aa97e5a1b7e337690db3abf85212c8d138e170922e7916ac8/covdefaults-2.3.0-py2.py3-none-any.whl", hash = "sha256:2832961f6ffcfe4b57c338bc3418a3526f495c26fb9c54565409c5532f7c41be", size = 5144, upload-time = "2023-03-05T16:43:33.245Z" },
]
[[package]]
name = "coverage"
version = "7.10.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/61/83/153f54356c7c200013a752ce1ed5448573dca546ce125801afca9e1ac1a4/coverage-7.10.5.tar.gz", hash = "sha256:f2e57716a78bc3ae80b2207be0709a3b2b63b9f2dcf9740ee6ac03588a2015b6", size = 821662, upload-time = "2025-08-23T14:42:44.78Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/08/4166ecfb60ba011444f38a5a6107814b80c34c717bc7a23be0d22e92ca09/coverage-7.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ef3b83594d933020f54cf65ea1f4405d1f4e41a009c46df629dd964fcb6e907c", size = 217106, upload-time = "2025-08-23T14:41:15.268Z" },
{ url = "https://files.pythonhosted.org/packages/25/d7/b71022408adbf040a680b8c64bf6ead3be37b553e5844f7465643979f7ca/coverage-7.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b96bfdf7c0ea9faebce088a3ecb2382819da4fbc05c7b80040dbc428df6af44", size = 217353, upload-time = "2025-08-23T14:41:16.656Z" },
{ url = "https://files.pythonhosted.org/packages/74/68/21e0d254dbf8972bb8dd95e3fe7038f4be037ff04ba47d6d1b12b37510ba/coverage-7.10.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:63df1fdaffa42d914d5c4d293e838937638bf75c794cf20bee12978fc8c4e3bc", size = 248350, upload-time = "2025-08-23T14:41:18.128Z" },
{ url = "https://files.pythonhosted.org/packages/90/65/28752c3a896566ec93e0219fc4f47ff71bd2b745f51554c93e8dcb659796/coverage-7.10.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8002dc6a049aac0e81ecec97abfb08c01ef0c1fbf962d0c98da3950ace89b869", size = 250955, upload-time = "2025-08-23T14:41:19.577Z" },
{ url = "https://files.pythonhosted.org/packages/a5/eb/ca6b7967f57f6fef31da8749ea20417790bb6723593c8cd98a987be20423/coverage-7.10.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63d4bb2966d6f5f705a6b0c6784c8969c468dbc4bcf9d9ded8bff1c7e092451f", size = 252230, upload-time = "2025-08-23T14:41:20.959Z" },
{ url = "https://files.pythonhosted.org/packages/bc/29/17a411b2a2a18f8b8c952aa01c00f9284a1fbc677c68a0003b772ea89104/coverage-7.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1f672efc0731a6846b157389b6e6d5d5e9e59d1d1a23a5c66a99fd58339914d5", size = 250387, upload-time = "2025-08-23T14:41:22.644Z" },
{ url = "https://files.pythonhosted.org/packages/c7/89/97a9e271188c2fbb3db82235c33980bcbc733da7da6065afbaa1d685a169/coverage-7.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3f39cef43d08049e8afc1fde4a5da8510fc6be843f8dea350ee46e2a26b2f54c", size = 248280, upload-time = "2025-08-23T14:41:24.061Z" },
{ url = "https://files.pythonhosted.org/packages/d1/c6/0ad7d0137257553eb4706b4ad6180bec0a1b6a648b092c5bbda48d0e5b2c/coverage-7.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2968647e3ed5a6c019a419264386b013979ff1fb67dd11f5c9886c43d6a31fc2", size = 249894, upload-time = "2025-08-23T14:41:26.165Z" },
{ url = "https://files.pythonhosted.org/packages/84/56/fb3aba936addb4c9e5ea14f5979393f1c2466b4c89d10591fd05f2d6b2aa/coverage-7.10.5-cp313-cp313-win32.whl", hash = "sha256:0d511dda38595b2b6934c2b730a1fd57a3635c6aa2a04cb74714cdfdd53846f4", size = 219536, upload-time = "2025-08-23T14:41:27.694Z" },
{ url = "https://files.pythonhosted.org/packages/fc/54/baacb8f2f74431e3b175a9a2881feaa8feb6e2f187a0e7e3046f3c7742b2/coverage-7.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:9a86281794a393513cf117177fd39c796b3f8e3759bb2764259a2abba5cce54b", size = 220330, upload-time = "2025-08-23T14:41:29.081Z" },
{ url = "https://files.pythonhosted.org/packages/64/8a/82a3788f8e31dee51d350835b23d480548ea8621f3effd7c3ba3f7e5c006/coverage-7.10.5-cp313-cp313-win_arm64.whl", hash = "sha256:cebd8e906eb98bb09c10d1feed16096700b1198d482267f8bf0474e63a7b8d84", size = 218961, upload-time = "2025-08-23T14:41:30.511Z" },
{ url = "https://files.pythonhosted.org/packages/d8/a1/590154e6eae07beee3b111cc1f907c30da6fc8ce0a83ef756c72f3c7c748/coverage-7.10.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0520dff502da5e09d0d20781df74d8189ab334a1e40d5bafe2efaa4158e2d9e7", size = 217819, upload-time = "2025-08-23T14:41:31.962Z" },
{ url = "https://files.pythonhosted.org/packages/0d/ff/436ffa3cfc7741f0973c5c89405307fe39b78dcf201565b934e6616fc4ad/coverage-7.10.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d9cd64aca68f503ed3f1f18c7c9174cbb797baba02ca8ab5112f9d1c0328cd4b", size = 218040, upload-time = "2025-08-23T14:41:33.472Z" },
{ url = "https://files.pythonhosted.org/packages/a0/ca/5787fb3d7820e66273913affe8209c534ca11241eb34ee8c4fd2aaa9dd87/coverage-7.10.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0913dd1613a33b13c4f84aa6e3f4198c1a21ee28ccb4f674985c1f22109f0aae", size = 259374, upload-time = "2025-08-23T14:41:34.914Z" },
{ url = "https://files.pythonhosted.org/packages/b5/89/21af956843896adc2e64fc075eae3c1cadb97ee0a6960733e65e696f32dd/coverage-7.10.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1b7181c0feeb06ed8a02da02792f42f829a7b29990fef52eff257fef0885d760", size = 261551, upload-time = "2025-08-23T14:41:36.333Z" },
{ url = "https://files.pythonhosted.org/packages/e1/96/390a69244ab837e0ac137989277879a084c786cf036c3c4a3b9637d43a89/coverage-7.10.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36d42b7396b605f774d4372dd9c49bed71cbabce4ae1ccd074d155709dd8f235", size = 263776, upload-time = "2025-08-23T14:41:38.25Z" },
{ url = "https://files.pythonhosted.org/packages/00/32/cfd6ae1da0a521723349f3129b2455832fc27d3f8882c07e5b6fefdd0da2/coverage-7.10.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b4fdc777e05c4940b297bf47bf7eedd56a39a61dc23ba798e4b830d585486ca5", size = 261326, upload-time = "2025-08-23T14:41:40.343Z" },
{ url = "https://files.pythonhosted.org/packages/4c/c4/bf8d459fb4ce2201e9243ce6c015936ad283a668774430a3755f467b39d1/coverage-7.10.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:42144e8e346de44a6f1dbd0a56575dd8ab8dfa7e9007da02ea5b1c30ab33a7db", size = 259090, upload-time = "2025-08-23T14:41:42.106Z" },
{ url = "https://files.pythonhosted.org/packages/f4/5d/a234f7409896468e5539d42234016045e4015e857488b0b5b5f3f3fa5f2b/coverage-7.10.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:66c644cbd7aed8fe266d5917e2c9f65458a51cfe5eeff9c05f15b335f697066e", size = 260217, upload-time = "2025-08-23T14:41:43.591Z" },
{ url = "https://files.pythonhosted.org/packages/f3/ad/87560f036099f46c2ddd235be6476dd5c1d6be6bb57569a9348d43eeecea/coverage-7.10.5-cp313-cp313t-win32.whl", hash = "sha256:2d1b73023854068c44b0c554578a4e1ef1b050ed07cf8b431549e624a29a66ee", size = 220194, upload-time = "2025-08-23T14:41:45.051Z" },
{ url = "https://files.pythonhosted.org/packages/36/a8/04a482594fdd83dc677d4a6c7e2d62135fff5a1573059806b8383fad9071/coverage-7.10.5-cp313-cp313t-win_amd64.whl", hash = "sha256:54a1532c8a642d8cc0bd5a9a51f5a9dcc440294fd06e9dda55e743c5ec1a8f14", size = 221258, upload-time = "2025-08-23T14:41:46.44Z" },
{ url = "https://files.pythonhosted.org/packages/eb/ad/7da28594ab66fe2bc720f1bc9b131e62e9b4c6e39f044d9a48d18429cc21/coverage-7.10.5-cp313-cp313t-win_arm64.whl", hash = "sha256:74d5b63fe3f5f5d372253a4ef92492c11a4305f3550631beaa432fc9df16fcff", size = 219521, upload-time = "2025-08-23T14:41:47.882Z" },
{ url = "https://files.pythonhosted.org/packages/08/b6/fff6609354deba9aeec466e4bcaeb9d1ed3e5d60b14b57df2a36fb2273f2/coverage-7.10.5-py3-none-any.whl", hash = "sha256:0be24d35e4db1d23d0db5c0f6a74a962e2ec83c426b5cac09f4234aadef38e4a", size = 208736, upload-time = "2025-08-23T14:42:43.145Z" },
]
[[package]]
name = "dill"
version = "0.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" },
]
[[package]]
name = "distlib"
version = "0.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
]
[[package]]
name = "filelock"
version = "3.19.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" },
]
[[package]]
name = "frozenlist"
version = "1.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" },
{ url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" },
{ url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" },
{ url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" },
{ url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" },
{ url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" },
{ url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" },
{ url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" },
{ url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" },
{ url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" },
{ url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" },
{ url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" },
{ url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" },
{ url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" },
{ url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" },
{ url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" },
{ url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" },
{ url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" },
{ url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" },
{ url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" },
{ url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" },
{ url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" },
{ url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" },
{ url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" },
{ url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" },
{ url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" },
{ url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" },
{ url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" },
{ url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" },
{ url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" },
{ url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" },
{ url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" },
{ url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" },
{ url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" },
{ url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" },
]
[[package]]
name = "identify"
version = "2.6.13"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/82/ca/ffbabe3635bb839aa36b3a893c91a9b0d368cb4d8073e03a12896970af82/identify-2.6.13.tar.gz", hash = "sha256:da8d6c828e773620e13bfa86ea601c5a5310ba4bcd65edf378198b56a1f9fb32", size = 99243, upload-time = "2025-08-09T19:35:00.6Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/ce/461b60a3ee109518c055953729bf9ed089a04db895d47e95444071dcdef2/identify-2.6.13-py2.py3-none-any.whl", hash = "sha256:60381139b3ae39447482ecc406944190f690d4a2997f2584062089848361b33b", size = 99153, upload-time = "2025-08-09T19:34:59.1Z" },
]
[[package]]
name = "idna"
version = "3.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
]
[[package]]
name = "iniconfig"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
]
[[package]]
name = "isort"
version = "6.0.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955, upload-time = "2025-02-26T21:13:16.955Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186, upload-time = "2025-02-26T21:13:14.911Z" },
]
[[package]]
name = "mccabe"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" },
]
[[package]]
name = "multidict"
version = "6.6.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/69/7f/0652e6ed47ab288e3756ea9c0df8b14950781184d4bd7883f4d87dd41245/multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd", size = 101843, upload-time = "2025-08-11T12:08:48.217Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3a/5d/e1db626f64f60008320aab00fbe4f23fc3300d75892a3381275b3d284580/multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e", size = 75848, upload-time = "2025-08-11T12:07:19.912Z" },
{ url = "https://files.pythonhosted.org/packages/4c/aa/8b6f548d839b6c13887253af4e29c939af22a18591bfb5d0ee6f1931dae8/multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657", size = 45060, upload-time = "2025-08-11T12:07:21.163Z" },
{ url = "https://files.pythonhosted.org/packages/eb/c6/f5e97e5d99a729bc2aa58eb3ebfa9f1e56a9b517cc38c60537c81834a73f/multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da", size = 43269, upload-time = "2025-08-11T12:07:22.392Z" },
{ url = "https://files.pythonhosted.org/packages/dc/31/d54eb0c62516776f36fe67f84a732f97e0b0e12f98d5685bebcc6d396910/multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa", size = 237158, upload-time = "2025-08-11T12:07:23.636Z" },
{ url = "https://files.pythonhosted.org/packages/c4/1c/8a10c1c25b23156e63b12165a929d8eb49a6ed769fdbefb06e6f07c1e50d/multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f", size = 257076, upload-time = "2025-08-11T12:07:25.049Z" },
{ url = "https://files.pythonhosted.org/packages/ad/86/90e20b5771d6805a119e483fd3d1e8393e745a11511aebca41f0da38c3e2/multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0", size = 240694, upload-time = "2025-08-11T12:07:26.458Z" },
{ url = "https://files.pythonhosted.org/packages/e7/49/484d3e6b535bc0555b52a0a26ba86e4d8d03fd5587d4936dc59ba7583221/multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879", size = 266350, upload-time = "2025-08-11T12:07:27.94Z" },
{ url = "https://files.pythonhosted.org/packages/bf/b4/aa4c5c379b11895083d50021e229e90c408d7d875471cb3abf721e4670d6/multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a", size = 267250, upload-time = "2025-08-11T12:07:29.303Z" },
{ url = "https://files.pythonhosted.org/packages/80/e5/5e22c5bf96a64bdd43518b1834c6d95a4922cc2066b7d8e467dae9b6cee6/multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f", size = 254900, upload-time = "2025-08-11T12:07:30.764Z" },
{ url = "https://files.pythonhosted.org/packages/17/38/58b27fed927c07035abc02befacab42491e7388ca105e087e6e0215ead64/multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5", size = 252355, upload-time = "2025-08-11T12:07:32.205Z" },
{ url = "https://files.pythonhosted.org/packages/d0/a1/dad75d23a90c29c02b5d6f3d7c10ab36c3197613be5d07ec49c7791e186c/multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438", size = 250061, upload-time = "2025-08-11T12:07:33.623Z" },
{ url = "https://files.pythonhosted.org/packages/b8/1a/ac2216b61c7f116edab6dc3378cca6c70dc019c9a457ff0d754067c58b20/multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e", size = 249675, upload-time = "2025-08-11T12:07:34.958Z" },
{ url = "https://files.pythonhosted.org/packages/d4/79/1916af833b800d13883e452e8e0977c065c4ee3ab7a26941fbfdebc11895/multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7", size = 261247, upload-time = "2025-08-11T12:07:36.588Z" },
{ url = "https://files.pythonhosted.org/packages/c5/65/d1f84fe08ac44a5fc7391cbc20a7cedc433ea616b266284413fd86062f8c/multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812", size = 257960, upload-time = "2025-08-11T12:07:39.735Z" },
{ url = "https://files.pythonhosted.org/packages/13/b5/29ec78057d377b195ac2c5248c773703a6b602e132a763e20ec0457e7440/multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a", size = 250078, upload-time = "2025-08-11T12:07:41.525Z" },
{ url = "https://files.pythonhosted.org/packages/c4/0e/7e79d38f70a872cae32e29b0d77024bef7834b0afb406ddae6558d9e2414/multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69", size = 41708, upload-time = "2025-08-11T12:07:43.405Z" },
{ url = "https://files.pythonhosted.org/packages/9d/34/746696dffff742e97cd6a23da953e55d0ea51fa601fa2ff387b3edcfaa2c/multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf", size = 45912, upload-time = "2025-08-11T12:07:45.082Z" },
{ url = "https://files.pythonhosted.org/packages/c7/87/3bac136181e271e29170d8d71929cdeddeb77f3e8b6a0c08da3a8e9da114/multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605", size = 43076, upload-time = "2025-08-11T12:07:46.746Z" },
{ url = "https://files.pythonhosted.org/packages/64/94/0a8e63e36c049b571c9ae41ee301ada29c3fee9643d9c2548d7d558a1d99/multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb", size = 82812, upload-time = "2025-08-11T12:07:48.402Z" },
{ url = "https://files.pythonhosted.org/packages/25/1a/be8e369dfcd260d2070a67e65dd3990dd635cbd735b98da31e00ea84cd4e/multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e", size = 48313, upload-time = "2025-08-11T12:07:49.679Z" },
{ url = "https://files.pythonhosted.org/packages/26/5a/dd4ade298674b2f9a7b06a32c94ffbc0497354df8285f27317c66433ce3b/multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f", size = 46777, upload-time = "2025-08-11T12:07:51.318Z" },
{ url = "https://files.pythonhosted.org/packages/89/db/98aa28bc7e071bfba611ac2ae803c24e96dd3a452b4118c587d3d872c64c/multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773", size = 229321, upload-time = "2025-08-11T12:07:52.965Z" },
{ url = "https://files.pythonhosted.org/packages/c7/bc/01ddda2a73dd9d167bd85d0e8ef4293836a8f82b786c63fb1a429bc3e678/multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e", size = 249954, upload-time = "2025-08-11T12:07:54.423Z" },
{ url = "https://files.pythonhosted.org/packages/06/78/6b7c0f020f9aa0acf66d0ab4eb9f08375bac9a50ff5e3edb1c4ccd59eafc/multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0", size = 228612, upload-time = "2025-08-11T12:07:55.914Z" },
{ url = "https://files.pythonhosted.org/packages/00/44/3faa416f89b2d5d76e9d447296a81521e1c832ad6e40b92f990697b43192/multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395", size = 257528, upload-time = "2025-08-11T12:07:57.371Z" },
{ url = "https://files.pythonhosted.org/packages/05/5f/77c03b89af0fcb16f018f668207768191fb9dcfb5e3361a5e706a11db2c9/multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45", size = 256329, upload-time = "2025-08-11T12:07:58.844Z" },
{ url = "https://files.pythonhosted.org/packages/cf/e9/ed750a2a9afb4f8dc6f13dc5b67b514832101b95714f1211cd42e0aafc26/multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb", size = 247928, upload-time = "2025-08-11T12:08:01.037Z" },
{ url = "https://files.pythonhosted.org/packages/1f/b5/e0571bc13cda277db7e6e8a532791d4403dacc9850006cb66d2556e649c0/multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5", size = 245228, upload-time = "2025-08-11T12:08:02.96Z" },
{ url = "https://files.pythonhosted.org/packages/f3/a3/69a84b0eccb9824491f06368f5b86e72e4af54c3067c37c39099b6687109/multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141", size = 235869, upload-time = "2025-08-11T12:08:04.746Z" },
{ url = "https://files.pythonhosted.org/packages/a9/9d/28802e8f9121a6a0804fa009debf4e753d0a59969ea9f70be5f5fdfcb18f/multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d", size = 243446, upload-time = "2025-08-11T12:08:06.332Z" },
{ url = "https://files.pythonhosted.org/packages/38/ea/6c98add069b4878c1d66428a5f5149ddb6d32b1f9836a826ac764b9940be/multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d", size = 252299, upload-time = "2025-08-11T12:08:07.931Z" },
{ url = "https://files.pythonhosted.org/packages/3a/09/8fe02d204473e14c0af3affd50af9078839dfca1742f025cca765435d6b4/multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0", size = 246926, upload-time = "2025-08-11T12:08:09.467Z" },
{ url = "https://files.pythonhosted.org/packages/37/3d/7b1e10d774a6df5175ecd3c92bff069e77bed9ec2a927fdd4ff5fe182f67/multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92", size = 243383, upload-time = "2025-08-11T12:08:10.981Z" },
{ url = "https://files.pythonhosted.org/packages/50/b0/a6fae46071b645ae98786ab738447de1ef53742eaad949f27e960864bb49/multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e", size = 47775, upload-time = "2025-08-11T12:08:12.439Z" },
{ url = "https://files.pythonhosted.org/packages/b2/0a/2436550b1520091af0600dff547913cb2d66fbac27a8c33bc1b1bccd8d98/multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4", size = 53100, upload-time = "2025-08-11T12:08:13.823Z" },
{ url = "https://files.pythonhosted.org/packages/97/ea/43ac51faff934086db9c072a94d327d71b7d8b40cd5dcb47311330929ef0/multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad", size = 45501, upload-time = "2025-08-11T12:08:15.173Z" },
{ url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" },
]
[[package]]
name = "mypy"
version = "1.17.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "pathspec" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8e/22/ea637422dedf0bf36f3ef238eab4e455e2a0dcc3082b5cc067615347ab8e/mypy-1.17.1.tar.gz", hash = "sha256:25e01ec741ab5bb3eec8ba9cdb0f769230368a22c959c4937360efb89b7e9f01", size = 3352570, upload-time = "2025-07-31T07:54:19.204Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/82/aec2fc9b9b149f372850291827537a508d6c4d3664b1750a324b91f71355/mypy-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93378d3203a5c0800c6b6d850ad2f19f7a3cdf1a3701d3416dbf128805c6a6a7", size = 11075338, upload-time = "2025-07-31T07:53:38.873Z" },
{ url = "https://files.pythonhosted.org/packages/07/ac/ee93fbde9d2242657128af8c86f5d917cd2887584cf948a8e3663d0cd737/mypy-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:15d54056f7fe7a826d897789f53dd6377ec2ea8ba6f776dc83c2902b899fee81", size = 10113066, upload-time = "2025-07-31T07:54:14.707Z" },
{ url = "https://files.pythonhosted.org/packages/5a/68/946a1e0be93f17f7caa56c45844ec691ca153ee8b62f21eddda336a2d203/mypy-1.17.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:209a58fed9987eccc20f2ca94afe7257a8f46eb5df1fb69958650973230f91e6", size = 11875473, upload-time = "2025-07-31T07:53:14.504Z" },
{ url = "https://files.pythonhosted.org/packages/9f/0f/478b4dce1cb4f43cf0f0d00fba3030b21ca04a01b74d1cd272a528cf446f/mypy-1.17.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:099b9a5da47de9e2cb5165e581f158e854d9e19d2e96b6698c0d64de911dd849", size = 12744296, upload-time = "2025-07-31T07:53:03.896Z" },
{ url = "https://files.pythonhosted.org/packages/ca/70/afa5850176379d1b303f992a828de95fc14487429a7139a4e0bdd17a8279/mypy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ffadfbe6994d724c5a1bb6123a7d27dd68fc9c059561cd33b664a79578e14", size = 12914657, upload-time = "2025-07-31T07:54:08.576Z" },
{ url = "https://files.pythonhosted.org/packages/53/f9/4a83e1c856a3d9c8f6edaa4749a4864ee98486e9b9dbfbc93842891029c2/mypy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:9a2b7d9180aed171f033c9f2fc6c204c1245cf60b0cb61cf2e7acc24eea78e0a", size = 9593320, upload-time = "2025-07-31T07:53:01.341Z" },
{ url = "https://files.pythonhosted.org/packages/1d/f3/8fcd2af0f5b806f6cf463efaffd3c9548a28f84220493ecd38d127b6b66d/mypy-1.17.1-py3-none-any.whl", hash = "sha256:a9f52c0351c21fe24c21d8c0eb1f62967b262d6729393397b6f443c3b773c3b9", size = 2283411, upload-time = "2025-07-31T07:53:24.664Z" },
]
[[package]]
name = "mypy-extensions"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
]
[[package]]
name = "nodeenv"
version = "1.9.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" },
]
[[package]]
name = "packaging"
version = "25.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
]
[[package]]
name = "pathspec"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
]
[[package]]
name = "platformdirs"
version = "4.3.8"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" },
]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]]
name = "pre-commit"
version = "4.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cfgv" },
{ name = "identify" },
{ name = "nodeenv" },
{ name = "pyyaml" },
{ name = "virtualenv" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792, upload-time = "2025-08-09T18:56:14.651Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/a5/987a405322d78a73b66e39e4a90e4ef156fd7141bf71df987e50717c321b/pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8", size = 220965, upload-time = "2025-08-09T18:56:13.192Z" },
]
[[package]]
name = "pre-commit-hooks"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ruamel-yaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/36/4d/93e63e48f8fd16d6c1e4cef5dabadcade4d1325c7fd6f29f075a4d2284f3/pre_commit_hooks-6.0.0.tar.gz", hash = "sha256:76d8370c006f5026cdd638a397a678d26dda735a3c88137e05885a020f824034", size = 28293, upload-time = "2025-08-09T19:25:04.6Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/12/46/eba9be9daa403fa94854ce16a458c29df9a01c6c047931c3d8be6016cd9a/pre_commit_hooks-6.0.0-py2.py3-none-any.whl", hash = "sha256:76161b76d321d2f8ee2a8e0b84c30ee8443e01376121fd1c90851e33e3bd7ee2", size = 41338, upload-time = "2025-08-09T19:25:03.513Z" },
]
[[package]]
name = "propcache"
version = "0.3.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" },
{ url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" },
{ url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" },
{ url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" },
{ url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" },
{ url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" },
{ url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" },
{ url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" },
{ url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" },
{ url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" },
{ url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" },
{ url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" },
{ url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" },
{ url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" },
{ url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" },
{ url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" },
{ url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" },
{ url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" },
{ url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" },
{ url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" },
{ url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" },
{ url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" },
{ url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" },
{ url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" },
{ url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" },
{ url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" },
{ url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" },
{ url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" },
{ url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" },
{ url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" },
{ url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" },
{ url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" },
{ url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" },
]
[[package]]
name = "pygments"
version = "2.19.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
]
[[package]]
name = "pylint"
version = "3.3.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "astroid" },
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "dill" },
{ name = "isort" },
{ name = "mccabe" },
{ name = "platformdirs" },
{ name = "tomlkit" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9d/58/1f614a84d3295c542e9f6e2c764533eea3f318f4592dc1ea06c797114767/pylint-3.3.8.tar.gz", hash = "sha256:26698de19941363037e2937d3db9ed94fb3303fdadf7d98847875345a8bb6b05", size = 1523947, upload-time = "2025-08-09T09:12:57.234Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2d/1a/711e93a7ab6c392e349428ea56e794a3902bb4e0284c1997cff2d7efdbc1/pylint-3.3.8-py3-none-any.whl", hash = "sha256:7ef94aa692a600e82fabdd17102b73fc226758218c97473c7ad67bd4cb905d83", size = 523153, upload-time = "2025-08-09T09:12:54.836Z" },
]
[[package]]
name = "pypaperless"
version = "0.0.0"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
{ name = "yarl" },
]
[package.dev-dependencies]
dev = [
{ name = "aioresponses" },
{ name = "codespell" },
{ name = "covdefaults" },
{ name = "coverage" },
{ name = "mypy" },
{ name = "pre-commit" },
{ name = "pre-commit-hooks" },
{ name = "pylint" },
{ name = "pytest" },
{ name = "pytest-aiohttp" },
{ name = "pytest-asyncio" },
{ name = "pytest-cov" },
{ name = "ruff" },
{ name = "yamllint" },
]
[package.metadata]
requires-dist = [
{ name = "aiohttp", specifier = ">=3.12.15" },
{ name = "yarl", specifier = ">=1.20.1" },
]
[package.metadata.requires-dev]
dev = [
{ name = "aioresponses", specifier = ">=0.7.8" },
{ name = "codespell", specifier = ">=2.4.1" },
{ name = "covdefaults", specifier = ">=2.3.0" },
{ name = "coverage", specifier = ">=7.10.5" },
{ name = "mypy", specifier = ">=1.17.1" },
{ name = "pre-commit", specifier = ">=4.3.0" },
{ name = "pre-commit-hooks", specifier = ">=6.0.0" },
{ name = "pylint", specifier = ">=3.3.8" },
{ name = "pytest", specifier = ">=8.4.1" },
{ name = "pytest-aiohttp", specifier = ">=1.1.0" },
{ name = "pytest-asyncio", specifier = ">=1.1.0" },
{ name = "pytest-cov", specifier = ">=6.2.1" },
{ name = "ruff", specifier = ">=0.12.10" },
{ name = "yamllint", specifier = ">=1.37.1" },
]
[[package]]
name = "pytest"
version = "8.4.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" },
]
[[package]]
name = "pytest-aiohttp"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/72/4b/d326890c153f2c4ce1bf45d07683c08c10a1766058a22934620bc6ac6592/pytest_aiohttp-1.1.0.tar.gz", hash = "sha256:147de8cb164f3fc9d7196967f109ab3c0b93ea3463ab50631e56438eab7b5adc", size = 12842, upload-time = "2025-01-23T12:44:04.465Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ba/0f/e6af71c02e0f1098eaf7d2dbf3ffdf0a69fc1e0ef174f96af05cef161f1b/pytest_aiohttp-1.1.0-py3-none-any.whl", hash = "sha256:f39a11693a0dce08dd6c542d241e199dd8047a6e6596b2bcfa60d373f143456d", size = 8932, upload-time = "2025-01-23T12:44:03.27Z" },
]
[[package]]
name = "pytest-asyncio"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4e/51/f8794af39eeb870e87a8c8068642fc07bce0c854d6865d7dd0f2a9d338c2/pytest_asyncio-1.1.0.tar.gz", hash = "sha256:796aa822981e01b68c12e4827b8697108f7205020f24b5793b3c41555dab68ea", size = 46652, upload-time = "2025-07-16T04:29:26.393Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/9d/bf86eddabf8c6c9cb1ea9a869d6873b46f105a5d292d3a6f7071f5b07935/pytest_asyncio-1.1.0-py3-none-any.whl", hash = "sha256:5fe2d69607b0bd75c656d1211f969cadba035030156745ee09e7d71740e58ecf", size = 15157, upload-time = "2025-07-16T04:29:24.929Z" },
]
[[package]]
name = "pytest-cov"
version = "6.2.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage" },
{ name = "pluggy" },
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" },
]
[[package]]
name = "pyyaml"
version = "6.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" },
{ url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" },
{ url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" },
{ url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" },
{ url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" },
{ url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" },
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" },
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" },
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
]
[[package]]
name = "ruamel-yaml"
version = "0.18.15"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ruamel-yaml-clib", marker = "platform_python_implementation == 'CPython'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3e/db/f3950f5e5031b618aae9f423a39bf81a55c148aecd15a34527898e752cf4/ruamel.yaml-0.18.15.tar.gz", hash = "sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700", size = 146865, upload-time = "2025-08-19T11:15:10.694Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/e5/f2a0621f1781b76a38194acae72f01e37b1941470407345b6e8653ad7640/ruamel.yaml-0.18.15-py3-none-any.whl", hash = "sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701", size = 119702, upload-time = "2025-08-19T11:15:07.696Z" },
]
[[package]]
name = "ruamel-yaml-clib"
version = "0.2.12"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/20/84/80203abff8ea4993a87d823a5f632e4d92831ef75d404c9fc78d0176d2b5/ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f", size = 225315, upload-time = "2024-10-20T10:10:56.22Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/29/00/4864119668d71a5fa45678f380b5923ff410701565821925c69780356ffa/ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a", size = 132011, upload-time = "2024-10-20T10:13:04.377Z" },
{ url = "https://files.pythonhosted.org/packages/7f/5e/212f473a93ae78c669ffa0cb051e3fee1139cb2d385d2ae1653d64281507/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475", size = 642488, upload-time = "2024-10-20T10:13:05.906Z" },
{ url = "https://files.pythonhosted.org/packages/1f/8f/ecfbe2123ade605c49ef769788f79c38ddb1c8fa81e01f4dbf5cf1a44b16/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef", size = 745066, upload-time = "2024-10-20T10:13:07.26Z" },
{ url = "https://files.pythonhosted.org/packages/e2/a9/28f60726d29dfc01b8decdb385de4ced2ced9faeb37a847bd5cf26836815/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6", size = 701785, upload-time = "2024-10-20T10:13:08.504Z" },
{ url = "https://files.pythonhosted.org/packages/84/7e/8e7ec45920daa7f76046578e4f677a3215fe8f18ee30a9cb7627a19d9b4c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf", size = 693017, upload-time = "2024-10-21T11:26:48.866Z" },
{ url = "https://files.pythonhosted.org/packages/c5/b3/d650eaade4ca225f02a648321e1ab835b9d361c60d51150bac49063b83fa/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1", size = 741270, upload-time = "2024-10-21T11:26:50.213Z" },
{ url = "https://files.pythonhosted.org/packages/87/b8/01c29b924dcbbed75cc45b30c30d565d763b9c4d540545a0eeecffb8f09c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01", size = 709059, upload-time = "2024-12-11T19:58:18.846Z" },
{ url = "https://files.pythonhosted.org/packages/30/8c/ed73f047a73638257aa9377ad356bea4d96125b305c34a28766f4445cc0f/ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6", size = 98583, upload-time = "2024-10-20T10:13:09.658Z" },
{ url = "https://files.pythonhosted.org/packages/b0/85/e8e751d8791564dd333d5d9a4eab0a7a115f7e349595417fd50ecae3395c/ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3", size = 115190, upload-time = "2024-10-20T10:13:10.66Z" },
]
[[package]]
name = "ruff"
version = "0.12.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/3b/eb/8c073deb376e46ae767f4961390d17545e8535921d2f65101720ed8bd434/ruff-0.12.10.tar.gz", hash = "sha256:189ab65149d11ea69a2d775343adf5f49bb2426fc4780f65ee33b423ad2e47f9", size = 5310076, upload-time = "2025-08-21T18:23:22.595Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/24/e7/560d049d15585d6c201f9eeacd2fd130def3741323e5ccf123786e0e3c95/ruff-0.12.10-py3-none-linux_armv6l.whl", hash = "sha256:8b593cb0fb55cc8692dac7b06deb29afda78c721c7ccfed22db941201b7b8f7b", size = 11935161, upload-time = "2025-08-21T18:22:26.965Z" },
{ url = "https://files.pythonhosted.org/packages/d1/b0/ad2464922a1113c365d12b8f80ed70fcfb39764288ac77c995156080488d/ruff-0.12.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ebb7333a45d56efc7c110a46a69a1b32365d5c5161e7244aaf3aa20ce62399c1", size = 12660884, upload-time = "2025-08-21T18:22:30.925Z" },
{ url = "https://files.pythonhosted.org/packages/d7/f1/97f509b4108d7bae16c48389f54f005b62ce86712120fd8b2d8e88a7cb49/ruff-0.12.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d59e58586829f8e4a9920788f6efba97a13d1fa320b047814e8afede381c6839", size = 11872754, upload-time = "2025-08-21T18:22:34.035Z" },
{ url = "https://files.pythonhosted.org/packages/12/ad/44f606d243f744a75adc432275217296095101f83f966842063d78eee2d3/ruff-0.12.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:822d9677b560f1fdeab69b89d1f444bf5459da4aa04e06e766cf0121771ab844", size = 12092276, upload-time = "2025-08-21T18:22:36.764Z" },
{ url = "https://files.pythonhosted.org/packages/06/1f/ed6c265e199568010197909b25c896d66e4ef2c5e1c3808caf461f6f3579/ruff-0.12.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b4a64f4062a50c75019c61c7017ff598cb444984b638511f48539d3a1c98db", size = 11734700, upload-time = "2025-08-21T18:22:39.822Z" },
{ url = "https://files.pythonhosted.org/packages/63/c5/b21cde720f54a1d1db71538c0bc9b73dee4b563a7dd7d2e404914904d7f5/ruff-0.12.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6f4064c69d2542029b2a61d39920c85240c39837599d7f2e32e80d36401d6e", size = 13468783, upload-time = "2025-08-21T18:22:42.559Z" },
{ url = "https://files.pythonhosted.org/packages/02/9e/39369e6ac7f2a1848f22fb0b00b690492f20811a1ac5c1fd1d2798329263/ruff-0.12.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:059e863ea3a9ade41407ad71c1de2badfbe01539117f38f763ba42a1206f7559", size = 14436642, upload-time = "2025-08-21T18:22:45.612Z" },
{ url = "https://files.pythonhosted.org/packages/e3/03/5da8cad4b0d5242a936eb203b58318016db44f5c5d351b07e3f5e211bb89/ruff-0.12.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bef6161e297c68908b7218fa6e0e93e99a286e5ed9653d4be71e687dff101cf", size = 13859107, upload-time = "2025-08-21T18:22:48.886Z" },
{ url = "https://files.pythonhosted.org/packages/19/19/dd7273b69bf7f93a070c9cec9494a94048325ad18fdcf50114f07e6bf417/ruff-0.12.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f1345fbf8fb0531cd722285b5f15af49b2932742fc96b633e883da8d841896b", size = 12886521, upload-time = "2025-08-21T18:22:51.567Z" },
{ url = "https://files.pythonhosted.org/packages/c0/1d/b4207ec35e7babaee62c462769e77457e26eb853fbdc877af29417033333/ruff-0.12.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f68433c4fbc63efbfa3ba5db31727db229fa4e61000f452c540474b03de52a9", size = 13097528, upload-time = "2025-08-21T18:22:54.609Z" },
{ url = "https://files.pythonhosted.org/packages/ff/00/58f7b873b21114456e880b75176af3490d7a2836033779ca42f50de3b47a/ruff-0.12.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:141ce3d88803c625257b8a6debf4a0473eb6eed9643a6189b68838b43e78165a", size = 13080443, upload-time = "2025-08-21T18:22:57.413Z" },
{ url = "https://files.pythonhosted.org/packages/12/8c/9e6660007fb10189ccb78a02b41691288038e51e4788bf49b0a60f740604/ruff-0.12.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f3fc21178cd44c98142ae7590f42ddcb587b8e09a3b849cbc84edb62ee95de60", size = 11896759, upload-time = "2025-08-21T18:23:00.473Z" },
{ url = "https://files.pythonhosted.org/packages/67/4c/6d092bb99ea9ea6ebda817a0e7ad886f42a58b4501a7e27cd97371d0ba54/ruff-0.12.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7d1a4e0bdfafcd2e3e235ecf50bf0176f74dd37902f241588ae1f6c827a36c56", size = 11701463, upload-time = "2025-08-21T18:23:03.211Z" },
{ url = "https://files.pythonhosted.org/packages/59/80/d982c55e91df981f3ab62559371380616c57ffd0172d96850280c2b04fa8/ruff-0.12.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e67d96827854f50b9e3e8327b031647e7bcc090dbe7bb11101a81a3a2cbf1cc9", size = 12691603, upload-time = "2025-08-21T18:23:06.935Z" },
{ url = "https://files.pythonhosted.org/packages/ad/37/63a9c788bbe0b0850611669ec6b8589838faf2f4f959647f2d3e320383ae/ruff-0.12.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ae479e1a18b439c59138f066ae79cc0f3ee250712a873d00dbafadaad9481e5b", size = 13164356, upload-time = "2025-08-21T18:23:10.225Z" },
{ url = "https://files.pythonhosted.org/packages/47/d4/1aaa7fb201a74181989970ebccd12f88c0fc074777027e2a21de5a90657e/ruff-0.12.10-py3-none-win32.whl", hash = "sha256:9de785e95dc2f09846c5e6e1d3a3d32ecd0b283a979898ad427a9be7be22b266", size = 11896089, upload-time = "2025-08-21T18:23:14.232Z" },
{ url = "https://files.pythonhosted.org/packages/ad/14/2ad38fd4037daab9e023456a4a40ed0154e9971f8d6aed41bdea390aabd9/ruff-0.12.10-py3-none-win_amd64.whl", hash = "sha256:7837eca8787f076f67aba2ca559cefd9c5cbc3a9852fd66186f4201b87c1563e", size = 13004616, upload-time = "2025-08-21T18:23:17.422Z" },
{ url = "https://files.pythonhosted.org/packages/24/3c/21cf283d67af33a8e6ed242396863af195a8a6134ec581524fd22b9811b6/ruff-0.12.10-py3-none-win_arm64.whl", hash = "sha256:cc138cc06ed9d4bfa9d667a65af7172b47840e1a98b02ce7011c391e54635ffc", size = 12074225, upload-time = "2025-08-21T18:23:20.137Z" },
]
[[package]]
name = "tomlkit"
version = "0.13.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]
[[package]]
name = "virtualenv"
version = "20.34.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
{ name = "filelock" },
{ name = "platformdirs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1c/14/37fcdba2808a6c615681cd216fecae00413c9dab44fb2e57805ecf3eaee3/virtualenv-20.34.0.tar.gz", hash = "sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a", size = 6003808, upload-time = "2025-08-13T14:24:07.464Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/06/04c8e804f813cf972e3262f3f8584c232de64f0cde9f703b46cf53a45090/virtualenv-20.34.0-py3-none-any.whl", hash = "sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026", size = 5983279, upload-time = "2025-08-13T14:24:05.111Z" },
]
[[package]]
name = "yamllint"
version = "1.37.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pathspec" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/46/f2/cd8b7584a48ee83f0bc94f8a32fea38734cefcdc6f7324c4d3bfc699457b/yamllint-1.37.1.tar.gz", hash = "sha256:81f7c0c5559becc8049470d86046b36e96113637bcbe4753ecef06977c00245d", size = 141613, upload-time = "2025-05-04T08:25:54.355Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/dd/b9/be7a4cfdf47e03785f657f94daea8123e838d817be76c684298305bd789f/yamllint-1.37.1-py3-none-any.whl", hash = "sha256:364f0d79e81409f591e323725e6a9f4504c8699ddf2d7263d8d2b539cd66a583", size = 68813, upload-time = "2025-05-04T08:25:52.552Z" },
]
[[package]]
name = "yarl"
version = "1.20.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
{ name = "multidict" },
{ name = "propcache" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" },
{ url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" },
{ url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" },
{ url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" },
{ url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" },
{ url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" },
{ url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" },
{ url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" },
{ url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" },
{ url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" },
{ url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" },
{ url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" },
{ url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" },
{ url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" },
{ url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" },
{ url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" },
{ url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" },
{ url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" },
{ url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" },
{ url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" },
{ url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" },
{ url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" },
{ url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" },
{ url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" },
{ url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" },
{ url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" },
{ url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" },
{ url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" },
{ url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" },
{ url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" },
{ url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" },
{ url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" },
{ url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" },
{ url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" },
{ url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" },
]