pax_global_header 0000666 0000000 0000000 00000000064 15025766213 0014521 g ustar 00root root 0000000 0000000 52 comment=79953284e6337c31b73ca5f811be19f913669dcc
paperless-api-4.1.1/ 0000775 0000000 0000000 00000000000 15025766213 0014271 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/.devcontainer/ 0000775 0000000 0000000 00000000000 15025766213 0017030 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/.devcontainer/devcontainer.json 0000664 0000000 0000000 00000003674 15025766213 0022416 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"
],
"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,
"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-4.1.1/.editorconfig 0000664 0000000 0000000 00000000274 15025766213 0016751 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-4.1.1/.gitattributes 0000664 0000000 0000000 00000000051 15025766213 0017160 0 ustar 00root root 0000000 0000000 * text eol=lf
*.py whitespace=error
paperless-api-4.1.1/.github/ 0000775 0000000 0000000 00000000000 15025766213 0015631 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/.github/labels.yml 0000664 0000000 0000000 00000005445 15025766213 0017626 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-4.1.1/.github/release-drafter.yml 0000664 0000000 0000000 00000002007 15025766213 0021420 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-4.1.1/.github/renovate.json 0000664 0000000 0000000 00000002171 15025766213 0020350 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-4.1.1/.github/workflows/ 0000775 0000000 0000000 00000000000 15025766213 0017666 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/.github/workflows/labels.yml 0000664 0000000 0000000 00000000734 15025766213 0021657 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@v4.2.2
- name: ๐ Run Label Syncer
uses: micnncim/action-label-syncer@v1.3.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
paperless-api-4.1.1/.github/workflows/linting.yml 0000664 0000000 0000000 00000004355 15025766213 0022064 0 ustar 00root root 0000000 0000000 ---
name: Linting
# yamllint disable-line rule:truthy
on:
push:
branches:
- main
paths:
- "**.py"
- "pyproject.toml"
- "uv.lock"
- "pypaperless/**"
- "tests/**"
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@v4.2.2
- 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-4.1.1/.github/workflows/lock.yml 0000664 0000000 0000000 00000000665 15025766213 0021350 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-4.1.1/.github/workflows/pr-labels.yml 0000664 0000000 0000000 00000001412 15025766213 0022270 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-4.1.1/.github/workflows/release-drafter.yml 0000664 0000000 0000000 00000000572 15025766213 0023462 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-4.1.1/.github/workflows/release.yml 0000664 0000000 0000000 00000002733 15025766213 0022036 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@v4.2.2
- 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-4.1.1/.github/workflows/stale.yml 0000664 0000000 0000000 00000002552 15025766213 0021525 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-4.1.1/.github/workflows/tests.yml 0000664 0000000 0000000 00000003316 15025766213 0021556 0 ustar 00root root 0000000 0000000 ---
name: Testing
# yamllint disable-line rule:truthy
on:
push:
branches:
- main
paths:
- "**.py"
- "pyproject.toml"
- "uv.lock"
- "pypaperless/**"
- "tests/**"
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@v4.2.2
- 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@v4.2.2
with:
fetch-depth: 0
- name: โฌ๏ธ Download coverage data
uses: actions/download-artifact@v4.3.0
- name: ๐ Upload coverage report
uses: codecov/codecov-action@v5.4.3
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
paperless-api-4.1.1/.github/workflows/typing.yml 0000664 0000000 0000000 00000001710 15025766213 0021722 0 ustar 00root root 0000000 0000000 ---
name: Typing
# yamllint disable-line rule:truthy
on:
push:
branches:
- main
paths:
- "**.py"
- "pyproject.toml"
- "uv.lock"
- "pypaperless/**"
- "tests/**"
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@v4.2.2
- 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-4.1.1/.gitignore 0000664 0000000 0000000 00000002715 15025766213 0016266 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-4.1.1/.pre-commit-config.yaml 0000664 0000000 0000000 00000007462 15025766213 0020563 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-4.1.1/.vscode/ 0000775 0000000 0000000 00000000000 15025766213 0015632 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/.vscode/launch.json 0000664 0000000 0000000 00000000462 15025766213 0020001 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-4.1.1/.yamllint 0000664 0000000 0000000 00000002400 15025766213 0016117 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-4.1.1/Dockerfile.dev 0000664 0000000 0000000 00000002371 15025766213 0017043 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-4.1.1/LICENSE.md 0000664 0000000 0000000 00000002056 15025766213 0015700 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-4.1.1/README.md 0000664 0000000 0000000 00000005275 15025766213 0015561 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`.
**v4 upgrade warning**
* We dropped support for Python `<=3.11`.
* Major changes in various classes occurred. Consider using Paperless-ngx `>=2.15.0`.
* Support for Paperless-ngx `<2.15.0` will end after 2025/07.
## Features
- Depends on aiohttp, works in async environments.
- Token authentication only. **No credentials anymore.**
- Request single resource items.
- Iterate over all resource items or request them page by page.
- Create, update and delete resource items.
- 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.
## 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/usage.md
[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-4.1.1/docs/ 0000775 0000000 0000000 00000000000 15025766213 0015221 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/docs/usage.md 0000664 0000000 0000000 00000056060 15025766213 0016656 0 ustar 00root root 0000000 0000000 # Usage
- [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](#request-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)
- [Special cases](#special-cases)
- [Document binary data](#document-binary-data)
- [Document custom fields (NEW)](#document-custom-fields-new)
- [Document metadata](#document-metadata)
- [Document notes](#document-notes)
- [Document searching](#document-searching)
- [Document suggestions](#document-suggestions)
- [Next available ASN](#next-available-asn)
- [Permissions](#permissions)
- [Toggle requesting permissions](#toggle-requesting-permissions)
- [Create item with permissions](#create-item-with-permissions)
- [Update permissions](#update-permissions)
- [System Status](#system-status)
## 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.
The code above executes one http request:
`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 |
| 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.
```
The code above executes two 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, ...]
```
The code above executes one http request:
`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.
```
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
```
The code above executes two 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.
```
The code above executes just one http request, and achieves the same:
`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`.
> [!NOTE]
> There are many filters available, _PyPaperless_ doesn't provide a complete list. I am working on that. 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
```
The code above executes one http request:
`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
```
The code above executes two http requests:
`PATCH` `http://localhost:8000/api/documents/23/`
`PUT` `http://localhost:8000/api/documents/23/`
> [!NOTE]
> 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
```
The code above executes one http request:
`DELETE` `http://localhost:8000/api/documents/23/`
## Special cases
Some Paperless-ngx resources provide more features as others, especially when it comes to `Documents`.
### Document binary data
You can access the binary data by using the following methods. They all return a `DownloadedDocument` class instance, which holds the 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()
```
The examples above result in the following 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/`
### Document custom fields (NEW)
When classifying your documents, you may want to add custom fields to them. Working with their values could be tricky and required you to loop through lists of field primary keys and their values. You also had to look up the custom fields by their primary key and parse the values according to their data types.
This is a typical `CustomFieldInstance` object provided by the Paperless-ngx API:
```python
{
# inside document object
"custom_fields": [
{
"value": 42,
"field": 11
},
],
}
```
This provides no details about the custom field except for its primary key.
**Provide a cache for all custom fields**
The benefit of this cache mechanism is that you don't have to request custom fields from the API multiple times. In addition, _PyPaperless_ makes use of this cache while mapping JSON objects to their classes in your Python program. You could use that cache in your code, as well.
```python
# initialize the cache to let PyPaperless resolve custom fields automatically
paperless.cache.custom_fields = await paperless.custom_fields.as_dict()
# fetch a document by primary key
document = await paperless.documents(1337)
doc_custom_fields = list(document.custom_fields)
```
Main difference between providing a cache or not:
```python
# without cache - no mapping, only basic information
print(doc_custom_fields[0])
#-> CustomFieldValue(field=11, value=42, name=None, data_type=None, extra_data=None)
# with cache - note the difference in the class type!
print(doc_custom_fields[0])
#-> CustomFieldIntegerValue(field=11, value=42, name='Any Number Field', data_type=, extra_data={'select_options': [None], 'default_currency': None})
```
**Example 2: Lookup a specific custom field by `CustomField` instance**
```python
# select a custom field to access its value
specific_custom_field = await paperless.custom_fields(1)
# and work with it
if specific_custom_field in document.custom_fields:
field = document.custom_fields.get(specific_custom_field)
# do something with: field.value
```
**Example 3: Lookup a specific custom field by its primary key**
```python
custom_field_id = 1
field = document.custom_fields.get(custom_field_id)
# do something with: field.value
```
> [!NOTE]
> Note that `document.custom_fields.get(...)` will raise an exception 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 4: Lookup a specific custom field or fallback to `None`**
```python
if field := document.custom_fields.default(23):
# do something with: field.value
```
**Example 5: Loop through all custom fields**
```python
for field in document.custom_fields:
# do something with: field.value
```
**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 uncommon data types.
* `CustomFieldDateValue.value`: The value is converted into a `datetime.datetime` object, if possible. It's a string or `None` otherwise.
* `CustomFieldDocumentLinkValue.value`: The value is a list of document ids (no `Document` objects at all)
* `CustomFieldSelectValue.labels`: Returns the list of labels of the `CustomField`.
* `CustomFieldSelectValue.label`: Returns the label for `value` (which is a reference to a label) or falls back to `None`.
### Document metadata
Paperless-ngx stores some metadata about your documents. If you wish to access that, there are two ways to access it.
**Example 1: Provide a primary key**
```python
metadata = await paperless.documents.metadata(23)
```
**Example 2: Already fetched item**
```python
document = await paperless.documents(23)
metadata = await document.get_metadata()
```
Both codes above execute one http request:
`GET` `https://localhost:8000/api/documents/23/metadata/`
### Document notes
Documents can be commented with so-called notes. Paperless-ngx supports requesting, creating and deleting those notes. _PyPaperless_ includes built-in support for it, too.
**Getting notes**
Document notes are always available as `list[DocumentNote]` after requesting them.
```python
# by primary key
list_of_notes = await paperless.documents.notes(23)
# by already fetched item
document = await paperless.documents(23)
list_of_notes = await document.notes()
```
The code above executes one http request:
`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.
```python
# by primary key
draft = paperless.documents.notes.draft(23)
# by already fetched item
document = await paperless.documents(23)
draft = document.notes.draft()
draft.note = "Lorem ipsum"
new_note_pk, document_pk = await draft.save()
#-> 42, 23
```
The code above executes one http request:
`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
```
The code above executes one http request:
`DELETE` `https://localhost:8000/api/documents/23/notes/?id=42`
### Document searching
If you want to search for documents, Paperless-ngx offers two possibilities to achieve that. _PyPaperless_ implements two iterable shortcuts for that.
**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
```
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`
**More like**
Search for similar documents like the permitted document primary key.
```python
async for document in paperless.documents.more_like(23):
# do something
```
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
```
### Document 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 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)
```
**Example 2: Already fetched item**
```python
document = await paperless.documents(23)
suggestions = await document.get_suggestions()
```
Both codes above execute one http request:
`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.
### Next available ASN
Simply returns the next available archive serial number as `int`.
```python
next_asn = await paperless.documents.get_next_asn()
#-> 1337
```
The code above executes one http request:
`GET` `https://localhost:8000/api/documents/next_asn/`
### Permissions
Some resources of Paperless-ngx support retrieving and updating of object-level permissions. 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 a toggle parameter.
#### Toggle requesting permissions
If you want to access the permissions table, you have to enable it one by one for each resource.
```python
paperless.documents.request_permissions = True
document = await paperless.documents(23)
if document.has_permissions:
print(document.permissions)
#-> PermissionTableType(
# view=PermissionSetType(users=[...], groups=[...],
# change=PermissionSetType(...)])
# )
for viewing_users in document.permissions.view.users:
# do something with the user
```
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
```
#### Create item with permissions
When creating new resource items, you can apply permissions by setting a `PermissionTableType` to the optional `set_permissions` field.
> [!NOTE]
> 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 the 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()
```
### System Status
As of release 2.6.0, Paperless-ngx supports displaying information about the current system health.
```python
info = await paperless.status()
```
The code above executes one http request:
`GET` `https://localhost:8000/api/status/`
paperless-api-4.1.1/pypaperless/ 0000775 0000000 0000000 00000000000 15025766213 0016640 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pypaperless/__init__.py 0000664 0000000 0000000 00000000111 15025766213 0020742 0 ustar 00root root 0000000 0000000 """PyPaperless."""
from .api import Paperless
__all__ = ("Paperless",)
paperless-api-4.1.1/pypaperless/api.py 0000664 0000000 0000000 00000034130 15025766213 0017764 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, cast
import aiohttp
import aiohttp.web_exceptions
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 Paperless:
"""Retrieves and manipulates data from and to Paperless via REST."""
_helpers_map: set[tuple[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),
}
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
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,
*,
session: aiohttp.ClientSession | None = None,
request_args: dict[str, Any] | 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._local_resources: set[PaperlessResource] = set()
self._remote_resources: set[PaperlessResource] = set()
self._request_args = request_args or {}
self._session = session
self._token = token
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_version(self) -> str | None:
"""Return the version of the Paperless host."""
return self._version
@property
def local_resources(self) -> set[PaperlessResource]:
"""Return a set of locally available resources."""
return self._local_resources
@property
def remote_resources(self) -> set[PaperlessResource]:
"""Return a set of available resources of the Paperless host."""
return self._remote_resources
@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 the connection to DRF and fetch the endpoints."""
async def _init_with_openapi_response() -> bool:
"""Connect to paperless and request the openapi schema."""
try:
async with self.request("get", API_PATH["api_schema"]) as res:
res.raise_for_status()
self._version = res.headers.get("x-version", None)
await res.read()
except aiohttp.ClientError:
return False
return True
async def _init_with_legacy_response() -> dict[str, str]:
"""Connect to paperless and request the entity dictionary (DRF)."""
async with self.request("get", API_PATH["index"]) as res:
try:
res.raise_for_status()
payload = await res.json()
except (aiohttp.ClientResponseError, ValueError) as exc:
raise InitializationError from exc
self._version = res.headers.get("x-version", None)
return cast("dict[str, str]", payload)
if await _init_with_openapi_response():
self.logger.debug("OpenAPI spec detected.")
self._remote_resources = {
res
for res in PaperlessResource
if res
not in {
PaperlessResource.UNKNOWN,
PaperlessResource.CONSUMPTION_TEMPLATES,
}
}
else:
payload = await _init_with_legacy_response()
self._remote_resources = set(map(PaperlessResource, payload))
# initialize helpers
for attribute, helper in self._helpers_map:
setattr(self, f"{attribute}", helper(self))
unused = self._remote_resources.difference(self._local_resources)
missing = self._local_resources.difference(self._remote_resources)
if len(unused) > 0:
self.logger.debug("Unused features: %s", ", ".join(unused))
if len(missing) > 0:
self.logger.warning(
"Outdated version detected. Consider pulling the latest version of Paperless-ngx."
)
self.logger.warning("Support for Paperless-ngx 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={API_VERSION}",
"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-4.1.1/pypaperless/const.py 0000664 0000000 0000000 00000010063 15025766213 0020340 0 ustar 00root root 0000000 0000000 """PyPaperless constants."""
from __future__ import annotations
from enum import StrEnum
API_VERSION = 7
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 = {
"api_schema": "/api/schema/",
"index": "/api/",
"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-4.1.1/pypaperless/exceptions.py 0000664 0000000 0000000 00000005676 15025766213 0021411 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-4.1.1/pypaperless/helpers.py 0000664 0000000 0000000 00000002005 15025766213 0020651 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-4.1.1/pypaperless/models/ 0000775 0000000 0000000 00000000000 15025766213 0020123 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pypaperless/models/__init__.py 0000664 0000000 0000000 00000002536 15025766213 0022242 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-4.1.1/pypaperless/models/base.py 0000664 0000000 0000000 00000010231 15025766213 0021404 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[ResourceT](PaperlessBase):
"""Base class for all helpers in PyPaperless."""
_resource: PaperlessResource
_resource_public: bool = True
def __init__(self, api: "Paperless") -> None:
"""Initialize a `HelperBase` instance."""
super().__init__(api)
if self._resource_public:
self._api.local_resources.add(self._resource)
@property
def is_available(self) -> bool:
"""Return if the attached endpoint is available, or not."""
return self._resource in self._api.remote_resources
@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-4.1.1/pypaperless/models/classifiers.py 0000664 0000000 0000000 00000015156 15025766213 0023014 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.datetime | 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[Correspondent],
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[DocumentType],
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[StoragePath],
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[Tag],
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-4.1.1/pypaperless/models/common.py 0000664 0000000 0000000 00000022647 15025766213 0022000 0 ustar 00root root 0000000 0000000 """PyPaperless common types."""
import contextlib
import datetime
from dataclasses import dataclass, field
from enum import Enum, StrEnum
from typing import TYPE_CHECKING, Any, TypedDict
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
@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.datetime | str | None = None
def __post_init__(self) -> None:
"""Convert the value to a datetime."""
if isinstance(self.value, str):
with contextlib.suppress(ValueError):
self.value = datetime.datetime.fromisoformat(self.value)
@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 CustomFieldSelectValue(CustomFieldValue):
"""Represent a select `CustomFieldValue`."""
value: int | 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
# 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-4.1.1/pypaperless/models/config.py 0000664 0000000 0000000 00000003675 15025766213 0021755 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[Config],
helpers.CallableMixin[Config],
):
"""Represent a factory for Paperless `Config` models."""
_api_path = API_PATH["config"]
_resource = PaperlessResource.CONFIG
_resource_cls = Config
paperless-api-4.1.1/pypaperless/models/custom_fields.py 0000664 0000000 0000000 00000003430 15025766213 0023335 0 ustar 00root root 0000000 0000000 """Provide `CustomField` 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 CustomFieldExtraData, CustomFieldType
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"))
@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[CustomField],
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-4.1.1/pypaperless/models/documents.py 0000664 0000000 0000000 00000055423 15025766213 0022507 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
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 (
CustomFieldBooleanValue,
CustomFieldDateValue,
CustomFieldDocumentLinkValue,
CustomFieldFloatValue,
CustomFieldIntegerValue,
CustomFieldSelectValue,
CustomFieldStringValue,
CustomFieldType,
CustomFieldValue,
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."""
CustomFieldValueMap: dict[CustomFieldType, type[CustomFieldValue]] = {
CustomFieldType.BOOLEAN: CustomFieldBooleanValue,
CustomFieldType.DATE: CustomFieldDateValue,
CustomFieldType.DOCUMENT_LINK: CustomFieldDocumentLinkValue,
CustomFieldType.FLOAT: CustomFieldFloatValue,
CustomFieldType.INTEGER: CustomFieldIntegerValue,
CustomFieldType.SELECT: CustomFieldSelectValue,
CustomFieldType.STRING: CustomFieldStringValue,
}
def __init__(self, api: "Paperless", data: list[dict[str, Any]]) -> None:
"""Initialize a `CustomFieldList` 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 = self.CustomFieldValueMap.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._data)
def __iter__(self) -> Iterator[CustomFieldValue]:
"""Iterate over custom fields.
Example:
-------
```python
for item in document.custom_fields:
# do something
```
"""
yield from self._fields
def default(self, field: int | CustomField) -> CustomFieldValue | None:
"""Access and return a `CustomField` from the `DocumentCustomFieldList`, or `None`."""
try:
return self.get(field)
except ItemNotFoundError:
return None
def get(self, field: int | CustomField) -> CustomFieldValue:
"""Access and return a `CustomField` from the `DocumentCustomFieldList`, or raise."""
item_id = field.id if isinstance(field, CustomField) else field
for item in self._fields:
if item.field == item_id:
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 self._data
@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.datetime | None = None
created_date: 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 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 == 204
@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[DocumentSuggestions]):
"""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[DownloadedDocument],
):
"""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[DocumentMeta],
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[DocumentNote]):
"""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"],
},
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[Document],
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-4.1.1/pypaperless/models/generators/ 0000775 0000000 0000000 00000000000 15025766213 0022274 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pypaperless/models/generators/__init__.py 0000664 0000000 0000000 00000000135 15025766213 0024404 0 ustar 00root root 0000000 0000000 """PyPaperless generators."""
from .page import PageGenerator
__all__ = ("PageGenerator",)
paperless-api-4.1.1/pypaperless/models/generators/page.py 0000664 0000000 0000000 00000004100 15025766213 0023555 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-4.1.1/pypaperless/models/mails.py 0000664 0000000 0000000 00000006207 15025766213 0021607 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[MailAccount],
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[MailRule],
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-4.1.1/pypaperless/models/mixins/ 0000775 0000000 0000000 00000000000 15025766213 0021432 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pypaperless/models/mixins/__init__.py 0000664 0000000 0000000 00000000045 15025766213 0023542 0 ustar 00root root 0000000 0000000 """Mixins for PyPaperless models."""
paperless-api-4.1.1/pypaperless/models/mixins/helpers/ 0000775 0000000 0000000 00000000000 15025766213 0023074 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pypaperless/models/mixins/helpers/__init__.py 0000664 0000000 0000000 00000000440 15025766213 0025203 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-4.1.1/pypaperless/models/mixins/helpers/callable.py 0000664 0000000 0000000 00000001761 15025766213 0025212 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-4.1.1/pypaperless/models/mixins/helpers/draftable.py 0000664 0000000 0000000 00000001624 15025766213 0025375 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-4.1.1/pypaperless/models/mixins/helpers/iterable.py 0000664 0000000 0000000 00000007336 15025766213 0025246 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-4.1.1/pypaperless/models/mixins/helpers/securable.py 0000664 0000000 0000000 00000001375 15025766213 0025421 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-4.1.1/pypaperless/models/mixins/models/ 0000775 0000000 0000000 00000000000 15025766213 0022715 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pypaperless/models/mixins/models/__init__.py 0000664 0000000 0000000 00000000635 15025766213 0025032 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-4.1.1/pypaperless/models/mixins/models/creatable.py 0000664 0000000 0000000 00000004175 15025766213 0025220 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-4.1.1/pypaperless/models/mixins/models/data_fields.py 0000664 0000000 0000000 00000000576 15025766213 0025536 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-4.1.1/pypaperless/models/mixins/models/deletable.py 0000664 0000000 0000000 00000001363 15025766213 0025213 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-4.1.1/pypaperless/models/mixins/models/securable.py 0000664 0000000 0000000 00000001346 15025766213 0025240 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-4.1.1/pypaperless/models/mixins/models/updatable.py 0000664 0000000 0000000 00000005121 15025766213 0025227 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-4.1.1/pypaperless/models/pages.py 0000664 0000000 0000000 00000005105 15025766213 0021575 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-4.1.1/pypaperless/models/permissions.py 0000664 0000000 0000000 00000004300 15025766213 0023045 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[Group],
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[User],
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-4.1.1/pypaperless/models/remote_version.py 0000664 0000000 0000000 00000001650 15025766213 0023537 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[RemoteVersion]):
"""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-4.1.1/pypaperless/models/saved_views.py 0000664 0000000 0000000 00000002737 15025766213 0023025 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[SavedView],
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-4.1.1/pypaperless/models/share_links.py 0000664 0000000 0000000 00000003476 15025766213 0023011 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[ShareLink],
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-4.1.1/pypaperless/models/statistics.py 0000664 0000000 0000000 00000002464 15025766213 0022675 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[Statistic]):
"""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-4.1.1/pypaperless/models/status.py 0000664 0000000 0000000 00000003414 15025766213 0022022 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[Status]):
"""Represent a factory for the Paperless `Status` model."""
_api_path = API_PATH["status"]
_resource = PaperlessResource.STATUS
_resource_public = False
_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-4.1.1/pypaperless/models/tasks.py 0000664 0000000 0000000 00000005314 15025766213 0021625 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[Task],
):
"""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-4.1.1/pypaperless/models/utils/ 0000775 0000000 0000000 00000000000 15025766213 0021263 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pypaperless/models/utils/__init__.py 0000664 0000000 0000000 00000017363 15025766213 0023406 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 date.fromisoformat(datestr)
def _dateobj_to_str(value: date | datetime) -> str:
"""Parse string from date objects."""
return value.isoformat()
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 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-4.1.1/pypaperless/models/workflows.py 0000664 0000000 0000000 00000013104 15025766213 0022531 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[WorkflowAction],
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[WorkflowTrigger],
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[Workflow],
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-4.1.1/pypaperless/py.typed 0000664 0000000 0000000 00000000000 15025766213 0020325 0 ustar 00root root 0000000 0000000 paperless-api-4.1.1/pyproject.toml 0000664 0000000 0000000 00000006720 15025766213 0017212 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"
dependencies = [
"aiohttp>=3.12.13",
"yarl>=1.20.1",
]
[dependency-groups]
dev = [
"aioresponses>=0.7.8",
"codespell>=2.4.1",
"covdefaults>=2.3.0",
"coverage>=7.9.1",
"mypy>=1.16.1",
"pre-commit>=4.2.0",
"pre-commit-hooks>=5.0.0",
"pylint>=3.3.7",
"pytest>=8.4.1",
"pytest-aiohttp>=1.1.0",
"pytest-asyncio>=1.0.0",
"pytest-cov>=6.2.1",
"ruff>=0.12.0",
"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-4.1.1/script/ 0000775 0000000 0000000 00000000000 15025766213 0015575 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/script/bootstrap 0000775 0000000 0000000 00000000326 15025766213 0017541 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-4.1.1/script/setup 0000775 0000000 0000000 00000001207 15025766213 0016663 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-4.1.1/tests/ 0000775 0000000 0000000 00000000000 15025766213 0015433 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/tests/__init__.py 0000664 0000000 0000000 00000007442 15025766213 0017553 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
# mypy: ignore-errors
@dataclass
class ResourceTestMapping:
"""Mapping for test cases."""
resource: str
helper_cls: type
model_cls: type
draft_cls: type | None = None
draft_defaults: dict[str, Any] | None = None
CONFIG_MAP = ResourceTestMapping(
PaperlessResource.CONFIG,
helpers.ConfigHelper,
models.Config,
)
CORRESPONDENT_MAP = ResourceTestMapping(
PaperlessResource.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,
helpers.CustomFieldHelper,
models.CustomField,
models.CustomFieldDraft,
{
"name": "New Custom Field",
"data_type": common.CustomFieldType.BOOLEAN,
},
)
DOCUMENT_MAP = ResourceTestMapping(
PaperlessResource.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,
helpers.DocumentTypeHelper,
models.DocumentType,
models.DocumentTypeDraft,
{
"name": "New Document Type",
"match": "",
"matching_algorithm": common.MatchingAlgorithmType.ANY,
"is_insensitive": True,
},
)
GROUP_MAP = ResourceTestMapping(
PaperlessResource.GROUPS,
helpers.GroupHelper,
models.Group,
)
MAIL_ACCOUNT_MAP = ResourceTestMapping(
PaperlessResource.MAIL_ACCOUNTS,
helpers.MailAccountHelper,
models.MailAccount,
)
MAIL_RULE_MAP = ResourceTestMapping(
PaperlessResource.MAIL_RULES,
helpers.MailRuleHelper,
models.MailRule,
)
SAVED_VIEW_MAP = ResourceTestMapping(
PaperlessResource.SAVED_VIEWS,
helpers.SavedViewHelper,
models.SavedView,
)
SHARE_LINK_MAP = ResourceTestMapping(
PaperlessResource.SHARE_LINKS,
helpers.ShareLinkHelper,
models.ShareLink,
models.ShareLinkDraft,
{
"expiration": None,
"document": 1,
"file_version": common.ShareLinkFileVersionType.ORIGINAL,
},
)
STATUS_MAP = ResourceTestMapping(
PaperlessResource.STATUS,
helpers.StatusHelper,
models.Status,
)
STORAGE_PATH_MAP = ResourceTestMapping(
PaperlessResource.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,
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,
helpers.TaskHelper,
models.Task,
)
USER_MAP = ResourceTestMapping(
PaperlessResource.USERS,
helpers.UserHelper,
models.User,
)
WORKFLOW_MAP = ResourceTestMapping(
PaperlessResource.WORKFLOWS,
helpers.WorkflowHelper,
models.Workflow,
)
paperless-api-4.1.1/tests/conftest.py 0000664 0000000 0000000 00000007730 15025766213 0017641 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 PATCHWORK
# 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_latest")
async def api_version_latest_fixture(
api_215: Paperless,
) -> AsyncGenerator[Paperless, Any]:
"""Return a Paperless object with latest version."""
return api_215
@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="api_00")
async def api_version_00_fixture(
resp: aioresponses,
api: Paperless,
) -> AsyncGenerator[Paperless, Any]:
"""Return a basic Paperless object."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['api_schema']}",
status=500,
headers={"X-Version": "0.0.0"},
payload=PATCHWORK["paths_v0_0_0"],
)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=200,
headers={"X-Version": "0.0.0"},
payload=PATCHWORK["paths_v0_0_0"],
)
async with api:
yield api
@pytest.fixture(name="api_18")
async def api_version_18_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,
headers={"X-Version": "1.8.0"},
payload=PATCHWORK["paths_v1_8_0"],
)
async with api:
yield api
@pytest.fixture(name="api_117")
async def api_version_117_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,
headers={"X-Version": "1.17.0"},
payload=PATCHWORK["paths_v1_17_0"],
)
async with api:
yield api
@pytest.fixture(name="api_20")
async def api_version_20_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,
headers={"X-Version": "2.0.0"},
payload=PATCHWORK["paths_v2_0_0"],
)
async with api:
yield api
@pytest.fixture(name="api_23")
async def api_version_23_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,
headers={"X-Version": "2.3.0"},
payload=PATCHWORK["paths_v2_3_0"],
)
async with api:
yield api
@pytest.fixture(name="api_26")
async def api_version_26_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,
headers={"X-Version": "2.6.0"},
payload=PATCHWORK["paths"],
)
async with api:
yield api
@pytest.fixture(name="api_215")
async def api_version_215_fixture(
resp: aioresponses,
api: Paperless,
) -> AsyncGenerator[Paperless, Any]:
"""Return a Paperless object with given version."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['api_schema']}",
status=200,
headers={"X-Version": "2.15.0"},
payload=PATCHWORK["schema"],
)
async with api:
yield api
paperless-api-4.1.1/tests/const.py 0000664 0000000 0000000 00000000376 15025766213 0017141 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-4.1.1/tests/data/ 0000775 0000000 0000000 00000000000 15025766213 0016344 5 ustar 00root root 0000000 0000000 paperless-api-4.1.1/tests/data/__init__.py 0000664 0000000 0000000 00000005024 15025766213 0020456 0 ustar 00root root 0000000 0000000 """Raw data constants."""
import json
from pathlib import Path
from .v0_0_0 import (
V0_0_0_CORRESPONDENTS,
V0_0_0_DOCUMENT_SUGGESTIONS,
V0_0_0_DOCUMENT_TYPES,
V0_0_0_DOCUMENTS,
V0_0_0_DOCUMENTS_METADATA,
V0_0_0_DOCUMENTS_SEARCH,
V0_0_0_GROUPS,
V0_0_0_MAIL_ACCOUNTS,
V0_0_0_MAIL_RULES,
V0_0_0_OBJECT_PERMISSIONS,
V0_0_0_PATHS,
V0_0_0_REMOTE_VERSION,
V0_0_0_SAVED_VIEWS,
V0_0_0_TAGS,
V0_0_0_TASKS,
V0_0_0_TOKEN,
V0_0_0_USERS,
)
from .v1_8_0 import V1_8_0_PATHS, V1_8_0_STORAGE_PATHS
from .v1_17_0 import V1_17_0_DOCUMENT_NOTES
from .v2_0_0 import (
V2_0_0_CONFIG,
V2_0_0_CUSTOM_FIELDS,
V2_0_0_PATHS,
V2_0_0_SHARE_LINKS,
)
from .v2_3_0 import (
V2_3_0_PATHS,
V2_3_0_WORKFLOW_ACTIONS,
V2_3_0_WORKFLOW_TRIGGERS,
V2_3_0_WORKFLOWS,
)
from .v2_6_0 import V2_6_0_STATUS
from .v2_15_0 import V2_15_0_STATISTICS
# mypy: ignore-errors
def _read_schema(filename: str) -> dict:
filepath = Path(f"tests/data/api-schema_{filename}.json")
with Path.open(filepath, mode="r", encoding="utf-8") as file:
return json.load(file)
_schema_v2_15_0 = _read_schema("v2.15.0")
PATCHWORK = {
# 0.0.0
"paths": V0_0_0_PATHS | V1_8_0_PATHS | V2_0_0_PATHS | V2_3_0_PATHS,
"paths_v0_0_0": V0_0_0_PATHS,
"paths_v1_8_0": V1_8_0_PATHS,
"paths_v2_0_0": V2_0_0_PATHS,
"paths_v2_3_0": V2_3_0_PATHS,
"correspondents": V0_0_0_CORRESPONDENTS,
"documents": V0_0_0_DOCUMENTS,
"documents_metadata": V0_0_0_DOCUMENTS_METADATA,
"documents_search": V0_0_0_DOCUMENTS_SEARCH,
"documents_suggestions": V0_0_0_DOCUMENT_SUGGESTIONS,
"document_types": V0_0_0_DOCUMENT_TYPES,
"groups": V0_0_0_GROUPS,
"mail_accounts": V0_0_0_MAIL_ACCOUNTS,
"mail_rules": V0_0_0_MAIL_RULES,
"object_permissions": V0_0_0_OBJECT_PERMISSIONS,
"saved_views": V0_0_0_SAVED_VIEWS,
"tags": V0_0_0_TAGS,
"tasks": V0_0_0_TASKS,
"token": V0_0_0_TOKEN,
"users": V0_0_0_USERS,
"remote_version": V0_0_0_REMOTE_VERSION,
# 1.8.0
"storage_paths": V1_8_0_STORAGE_PATHS,
# 1.17.0
"document_notes": V1_17_0_DOCUMENT_NOTES,
# 2.0.0
"config": V2_0_0_CONFIG,
"custom_fields": V2_0_0_CUSTOM_FIELDS,
"share_links": V2_0_0_SHARE_LINKS,
# 2.3.0
"workflows": V2_3_0_WORKFLOWS,
"workflow_actions": V2_3_0_WORKFLOW_ACTIONS,
"workflow_triggers": V2_3_0_WORKFLOW_TRIGGERS,
# 2.6.0
"status": V2_6_0_STATUS,
# 2.15.0
"schema": _schema_v2_15_0,
"statistics": V2_15_0_STATISTICS,
}
__all__ = ("PATCHWORK",)
paperless-api-4.1.1/tests/data/api-schema_v2.15.0.json 0000664 0000000 0000000 00002127633 15025766213 0022255 0 ustar 00root root 0000000 0000000 {
"openapi": "3.0.3",
"info": {
"title": "Paperless-ngx REST API",
"version": "6.0.0 (7)",
"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": ""
}
}
},
"post": {
"operationId": "config_create",
"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": {
"201": {
"content": {
"application/json": {
"schema": {
"$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": "Pass a user object to serializer",
"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-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": "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"
}
},
{
"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": "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": ""
}
}
}
},
"/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_retrieve",
"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
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"note": {
"type": "string"
},
"created": {
"type": "string",
"format": "date-time"
},
"user": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"username": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
}
}
}
}
}
}
}
},
"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
}
],
"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": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"note": {
"type": "string"
},
"created": {
"type": "string",
"format": "date-time"
},
"user": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"username": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
}
}
}
}
}
}
}
},
"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
}
],
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"note": {
"type": "string"
},
"created": {
"type": "string",
"format": "date-time"
},
"user": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"username": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
}
}
}
}
}
}
}
},
"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": "Pass a user object to serializer",
"tags": [
"documents"
],
"security": [
{
"PaperelessBasicAuthentication": []
},
{
"tokenAuth": []
},
{
"cookieAuth": []
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Document"
}
}
},
"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_accounts_process_create",
"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": ""
}
}
}
},
"/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_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
}
],
"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",
"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",
"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"
],
"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": ""
}
}
}
},
"/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
},
"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)$"
}
},
"required": [
"id",
"user_args"
]
},
"ApplicationConfigurationRequest": {
"type": "object",
"properties": {
"user_args": {
"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)$"
}
},
"required": [
"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-time",
"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-time"
},
"created_date": {
"type": "string",
"format": "date"
},
"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-time"
},
"created_date": {
"type": "string",
"format": "date"
},
"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"
]
},
"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"
]
},
"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"
],
"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"
},
"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"
},
"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]"
}
}
},
"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
},
"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)$"
}
}
},
"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-time"
},
"created_date": {
"type": "string",
"format": "date"
},
"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
},
"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
}
}
},
"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": 0,
"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
},
"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": [
"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": {
"nullable": true
}
},
"required": [
"id"
]
},
"UiSettingsViewRequest": {
"type": "object",
"properties": {
"settings": {
"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": 0,
"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": 0,
"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-4.1.1/tests/data/v0_0_0.py 0000664 0000000 0000000 00000074631 15025766213 0017714 0 ustar 00root root 0000000 0000000 """Raw data constants for all Paperless versions."""
# mypy: ignore-errors
from tests.const import PAPERLESS_TEST_TOKEN, PAPERLESS_TEST_URL
V0_0_0_REMOTE_VERSION = {"version": "v2.15.3", "update_available": True}
V0_0_0_TOKEN = {"token": PAPERLESS_TEST_TOKEN}
V0_0_0_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/",
}
V0_0_0_OBJECT_PERMISSIONS = {
"view": {
"users": [1, 2],
"groups": [],
},
"change": {
"users": [],
"groups": [1],
},
}
V0_0_0_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-18T00:00:00+00:00",
"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-07T23:00:00+00:00",
"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-11T00:00:00+00:00",
"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-18T22:00:00+00:00",
"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-28T00:00:00+00:00",
"owner": None,
"user_can_change": True,
},
],
}
V0_0_0_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-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": [],
},
{
"id": 2,
"correspondent": 2,
"document_type": 1,
"storage_path": 1,
"title": "Salty Document",
"content": "OCRd text from document",
"tags": [1],
"created": "2022-01-07T00:00:00+00:00",
"created_date": "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},
],
},
],
}
V0_0_0_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,
},
},
],
}
V0_0_0_DOCUMENTS_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",
},
],
}
V0_0_0_DOCUMENT_SUGGESTIONS = {
"correspondents": [26],
"tags": [
1,
2,
3,
],
"document_types": [4],
"storage_paths": [
3,
5,
],
"dates": [
"2022-01-07",
"2023-01-07",
],
}
V0_0_0_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,
},
],
}
V0_0_0_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",
],
},
],
}
V0_0_0_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,
}
],
}
V0_0_0_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,
}
],
}
V0_0_0_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,
},
],
}
V0_0_0_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,
},
],
}
V0_0_0_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",
},
]
V0_0_0_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-4.1.1/tests/data/v1_17_0.py 0000664 0000000 0000000 00000001603 15025766213 0017772 0 ustar 00root root 0000000 0000000 """Raw data constants for Paperless versions >= 1.17.0."""
V1_17_0_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-4.1.1/tests/data/v1_8_0.py 0000664 0000000 0000000 00000004204 15025766213 0017712 0 ustar 00root root 0000000 0000000 """Raw data constants for Paperless versions >= 1.8.0."""
from tests.const import PAPERLESS_TEST_URL
V1_8_0_PATHS = {
"storage_paths": f"{PAPERLESS_TEST_URL}/api/storage_paths/",
}
V1_8_0_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-4.1.1/tests/data/v2_0_0.py 0000664 0000000 0000000 00000007501 15025766213 0017706 0 ustar 00root root 0000000 0000000 """Raw data constants for Paperless versions >= 2.0.0."""
from tests.const import PAPERLESS_TEST_URL
V2_0_0_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/",
}
V2_0_0_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,
}
]
V2_0_0_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"},
],
}
V2_0_0_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.096456+00:00",
"expiration": "2023-12-18T14:06:49.064000+00:00",
"slug": "GMIFR9WVPe7a0FAltmrAdmVsrrTzH6Z9yFi2jufhi5yCTAMWfF",
"document": 1,
"file_version": "original",
},
{
"id": 2,
"created": "2023-12-11T14:06:53.583496+00:00",
"expiration": "2024-01-10T14:06:53.558000+00:00",
"slug": "Px2h3mrkIvExyTE8M8usrTLv3jtTb4MnLJ4eTAxcjy2FUmuDLq",
"document": 2,
"file_version": "original",
},
{
"id": 3,
"created": "2023-12-11T14:06:55.984583+00:00",
"expiration": None,
"slug": "bDnxeQ4UmlFVUYCDrb1KBLbE4HVSW8jw3CLElcwPyAncV5eiI+00:00",
"document": 1,
"file_version": "original",
},
{
"id": 4,
"created": "2023-12-11T14:07:01.448813+00:00",
"expiration": "2023-12-12T14:07:01.423000+00:00",
"slug": "HfzHhDzA03ZQg4t4TAlOuup59qgQA18Zjbb9eOE06PZ8KTjgOb",
"document": 2,
"file_version": "archive",
},
{
"id": 5,
"created": "2023-12-11T14:11:50.710369+00:00",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
{
"id": 6,
"created": "2023-12-11T14:11:50.710369+00:00",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
{
"id": 7,
"created": "2023-12-11T14:11:50.710369+00:00",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
{
"id": 8,
"created": "2023-12-11T14:11:50.710369+00:00",
"expiration": None,
"slug": "7PIGEZbeFv5yIrnpSVwj1QeXiJu0IZCiEWGIV4aUHQrfUQtXne",
"document": 1,
"file_version": "archive",
},
],
}
paperless-api-4.1.1/tests/data/v2_15_0.py 0000664 0000000 0000000 00000001134 15025766213 0017770 0 ustar 00root root 0000000 0000000 """Raw data constants for Paperless versions >= 2.15.0."""
# mypy: ignore-errors
V2_15_0_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-4.1.1/tests/data/v2_3_0.py 0000664 0000000 0000000 00000012206 15025766213 0017707 0 ustar 00root root 0000000 0000000 """Raw data constants for Paperless versions >= 2.3.0."""
from tests.const import PAPERLESS_TEST_URL
# mypy: ignore-errors
V2_3_0_PATHS = {
"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/",
}
V2_3_0_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": [],
}
],
},
],
}
V2_3_0_WORKFLOW_ACTIONS = {
"count": 0,
"next": None,
"previous": None,
"all": [],
"results": [],
}
for wf in V2_3_0_WORKFLOWS["results"]:
V2_3_0_WORKFLOW_ACTIONS["count"] += 1
for act in wf["actions"]:
V2_3_0_WORKFLOW_ACTIONS["all"].append(act["id"])
V2_3_0_WORKFLOW_ACTIONS["results"].append(act)
V2_3_0_WORKFLOW_TRIGGERS = {
"count": 0,
"next": None,
"previous": None,
"all": [],
"results": [],
}
for wf in V2_3_0_WORKFLOWS["results"]:
V2_3_0_WORKFLOW_TRIGGERS["count"] += 1
for act in wf["triggers"]:
V2_3_0_WORKFLOW_TRIGGERS["all"].append(act["id"])
V2_3_0_WORKFLOW_TRIGGERS["results"].append(act)
paperless-api-4.1.1/tests/data/v2_6_0.py 0000664 0000000 0000000 00000002054 15025766213 0017712 0 ustar 00root root 0000000 0000000 """Raw data constants for Paperless versions >= 2.6.0."""
# mypy: ignore-errors
V2_6_0_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-4.1.1/tests/ruff.toml 0000664 0000000 0000000 00000000667 15025766213 0017303 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-4.1.1/tests/test_common.py 0000664 0000000 0000000 00000047636 15025766213 0020354 0 ustar 00root root 0000000 0000000 """Paperless common tests."""
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 Page
from pypaperless.models.base import HelperBase, PaperlessModel
from pypaperless.models.common import (
CustomFieldDateValue,
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 PATCHWORK
# 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['api_schema']}",
status=200,
payload=PATCHWORK["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['api_schema']}",
status=500,
payload=PATCHWORK["paths"],
)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['index']}",
status=200,
payload=PATCHWORK["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
assert isinstance(api.local_resources, set)
assert isinstance(api.remote_resources, set)
async def test_helper_avail_00(self, api_00: Paperless) -> None:
"""Test availability of helpers against specific api version."""
assert not api_00.custom_fields.is_available
assert not api_00.workflows.is_available
async def test_helper_avail_latest(self, api_latest: Paperless) -> None:
"""Test availability of helpers against specific api version."""
assert api_latest.custom_fields.is_available
assert api_latest.workflows.is_available
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['api_schema']}",
status=500,
payload=PATCHWORK["paths"],
)
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['api_schema']}",
status=500,
payload=PATCHWORK["paths"],
)
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['api_schema']}",
status=500,
payload=PATCHWORK["paths"],
)
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['api_schema']}",
status=500,
payload=PATCHWORK["paths"],
)
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=PATCHWORK["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=PATCHWORK["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_value_types(self) -> None:
"""Test custom field value types."""
# check date transformation
test = CustomFieldDateValue(value="1900-01-02T02:03:04")
assert isinstance(test.value, datetime)
# check label properties
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-4.1.1/tests/test_models_matrix.py 0000664 0000000 0000000 00000035637 15025766213 0021731 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 PATCHWORK
# 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test pages."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
page = await anext(aiter(getattr(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test as_dict."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
items = await getattr(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test as_dict."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
items = await getattr(api_latest, mapping.resource).as_list()
for obj in items:
assert isinstance(obj, mapping.model_cls)
async def test_iter(
self, resp: aioresponses, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test iter."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
async for item in getattr(api_latest, mapping.resource):
assert isinstance(item, mapping.model_cls)
async def test_all(
self, resp: aioresponses, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test all."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
items = await getattr(api_latest, mapping.resource).all()
assert isinstance(items, list)
for item in items:
assert isinstance(item, int)
async def test_call(
self, resp: aioresponses, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload=PATCHWORK[mapping.resource]["results"][0],
)
item = await getattr(api_latest, 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(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test pages."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
page = await anext(aiter(getattr(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test iter."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
async for item in getattr(api_latest, mapping.resource):
assert isinstance(item, mapping.model_cls)
async def test_all(
self, resp: aioresponses, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test all."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource]}" + r"\?.*$"),
status=200,
payload=PATCHWORK[mapping.resource],
)
items = await getattr(api_latest, mapping.resource).all()
assert isinstance(items, list)
for item in items:
assert isinstance(item, int)
async def test_reduce(
self, resp: aioresponses, api_latest: 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=PATCHWORK[mapping.resource],
)
async with getattr(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload=PATCHWORK[mapping.resource]["results"][0],
)
item = await getattr(api_latest, 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(api_latest, mapping.resource)(1337)
async def test_create(
self, resp: aioresponses, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test create."""
draft = getattr(api_latest, 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(PATCHWORK[mapping.resource]["results"]),
**draft._serialize(), # pylint: disable=protected-access
},
)
new_pk = await draft.save()
assert new_pk >= 1
async def test_udpate(
self, resp: aioresponses, api_latest: 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=PATCHWORK[mapping.resource]["results"][0],
)
to_update = await getattr(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test delete."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH[mapping.resource + '_single']}".format(pk=1),
status=200,
payload=PATCHWORK[mapping.resource]["results"][0],
)
to_delete = await getattr(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test permissions."""
getattr(api_latest, mapping.resource).request_permissions = True
assert getattr(api_latest, 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={
**PATCHWORK[mapping.resource]["results"][0],
"permissions": PATCHWORK["object_permissions"],
},
)
item = await getattr(api_latest, 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={
**PATCHWORK[mapping.resource],
"results": [
{**item, "permissions": PATCHWORK["object_permissions"]}
for item in PATCHWORK[mapping.resource]["results"]
],
},
)
async for item in getattr(api_latest, 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, api_latest: Paperless, mapping: ResourceTestMapping
) -> None:
"""Test permission changes."""
getattr(api_latest, mapping.resource).request_permissions = True
assert getattr(api_latest, 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={
**PATCHWORK[mapping.resource]["results"][0],
"permissions": PATCHWORK["object_permissions"],
},
)
item = await getattr(api_latest, 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-4.1.1/tests/test_models_specific.py 0000664 0000000 0000000 00000044465 15025766213 0022211 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 (
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 PATCHWORK
# mypy: ignore-errors
# test models/config.py
class TestModelConfig:
"""Config test cases."""
async def test_call(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['config_single']}".format(pk=1),
status=200,
payload=PATCHWORK["config"][0],
)
item = await api_latest.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 api_latest.config(1337)
# test models/documents.py
class TestModelDocuments:
"""Documents test cases."""
async def test_lazy(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test laziness."""
document = Document(api_latest, data={"id": 1})
assert not document.is_fetched
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
await document.load()
assert document.is_fetched
async def test_create(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test create."""
defaults = DOCUMENT_MAP.draft_defaults or {}
draft = api_latest.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_udpate(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test update."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
to_update = await api_latest.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, api_latest: Paperless) -> None:
"""Test delete."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
to_delete = await api_latest.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, api_latest: Paperless) -> None:
"""Test meta."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
document = await api_latest.documents(1)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_meta']}".format(pk=1),
status=200,
payload=PATCHWORK["documents_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, api_latest: Paperless) -> None:
"""Test files."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
document = await api_latest.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, api_latest: Paperless) -> None:
"""Test suggestions."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
document = await api_latest.documents(1)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_suggestions']}".format(pk=1),
status=200,
payload=PATCHWORK["documents_suggestions"],
)
suggestions = await document.get_suggestions()
assert isinstance(suggestions, DocumentSuggestions)
async def test_get_next_an(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test get next asn."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_next_asn']}",
status=200,
payload=1337,
)
asn = await api_latest.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 api_latest.documents.get_next_asn()
async def test_searching(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test searching."""
# search
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['documents']}" + r"\?.*query.*$"),
status=200,
payload=PATCHWORK["documents_search"],
)
async for item in api_latest.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=PATCHWORK["documents_search"],
)
async for item in api_latest.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, api_latest: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
item = await api_latest.documents(1)
assert isinstance(item, Document)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_notes']}".format(pk=1),
status=200,
payload=PATCHWORK["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 api_latest.documents.notes()
async def test_note_create(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test create."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
item = await api_latest.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=PATCHWORK["document_notes"],
)
result = await draft.save()
assert isinstance(result, tuple)
async def test_note_delete(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test delete."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=1),
status=200,
payload=PATCHWORK["documents"]["results"][0],
)
item = await api_latest.documents(1)
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_notes']}".format(pk=1),
status=200,
payload=PATCHWORK["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_fields(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test custom fields."""
# set custom fields cache
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['custom_fields']}" + r"\?.*$"),
status=200,
payload=PATCHWORK["custom_fields"],
)
api_latest.cache.custom_fields = await api_latest.custom_fields.as_dict()
# request document
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['documents_single']}".format(pk=2),
status=200,
payload=PATCHWORK["documents"]["results"][1],
)
item = await api_latest.documents(2)
assert isinstance(item.custom_fields, DocumentCustomFieldList)
# test if custom field is in document custom field values
test_cf = CustomField.create_with_data(
api=api_latest,
data=PATCHWORK["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 models/remote_version.py
class TestModelVersion:
"""Version test cases."""
async def test_call(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['remote_version']}",
status=200,
payload=PATCHWORK["remote_version"],
)
remote_version = await api_latest.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, api_latest: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['statistics']}",
status=200,
payload=PATCHWORK["statistics"],
)
stats = await api_latest.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, api_latest: Paperless) -> None:
"""Test call."""
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['status']}",
status=200,
payload=PATCHWORK["status"],
)
status = await api_latest.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, api_latest: 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(api_latest, data=data, fetched=True)
assert status.has_errors is False
# lets set something to ERROR
data["database"]["status"] = "ERROR"
status = Status.create_with_data(api_latest, 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(api_latest, 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, api_latest: Paperless) -> None:
"""Test iter."""
resp.get(
re.compile(r"^" + f"{PAPERLESS_TEST_URL}{API_PATH['tasks']}" + r".*$"),
status=200,
payload=PATCHWORK["tasks"],
)
async for item in api_latest.tasks:
assert isinstance(item, Task)
async def test_call(self, resp: aioresponses, api_latest: Paperless) -> None:
"""Test call."""
# by pk
resp.get(
f"{PAPERLESS_TEST_URL}{API_PATH['tasks_single']}".format(pk=1),
status=200,
payload=PATCHWORK["tasks"][0],
)
item = await api_latest.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=PATCHWORK["tasks"],
)
item = await api_latest.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 api_latest.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 api_latest.tasks("dummy-not-found")
# test models/workflows.py
class TestModelWorkflows:
"""Tasks test cases."""
async def test_helpers(self, api_latest: Paperless) -> None:
"""Test helpers."""
assert isinstance(api_latest.workflows.actions, WorkflowActionHelper)
assert isinstance(api_latest.workflows.triggers, WorkflowTriggerHelper)
paperless-api-4.1.1/uv.lock 0000664 0000000 0000000 00000313372 15025766213 0015606 0 ustar 00root root 0000000 0000000 version = 1
revision = 2
requires-python = ">=3.13, <4"
[[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.13"
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/42/6e/ab88e7cb2a4058bed2f7870276454f85a7c56cd6da79349eb314fc7bbcaa/aiohttp-3.12.13.tar.gz", hash = "sha256:47e2da578528264a12e4e3dd8dd72a7289e5f812758fe086473fab037a10fcce", size = 7819160, upload-time = "2025-06-14T15:15:41.354Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/11/0f/db19abdf2d86aa1deec3c1e0e5ea46a587b97c07a16516b6438428b3a3f8/aiohttp-3.12.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d4a18e61f271127465bdb0e8ff36e8f02ac4a32a80d8927aa52371e93cd87938", size = 694910, upload-time = "2025-06-14T15:14:30.604Z" },
{ url = "https://files.pythonhosted.org/packages/d5/81/0ab551e1b5d7f1339e2d6eb482456ccbe9025605b28eed2b1c0203aaaade/aiohttp-3.12.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:532542cb48691179455fab429cdb0d558b5e5290b033b87478f2aa6af5d20ace", size = 472566, upload-time = "2025-06-14T15:14:32.275Z" },
{ url = "https://files.pythonhosted.org/packages/34/3f/6b7d336663337672d29b1f82d1f252ec1a040fe2d548f709d3f90fa2218a/aiohttp-3.12.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d7eea18b52f23c050ae9db5d01f3d264ab08f09e7356d6f68e3f3ac2de9dfabb", size = 464856, upload-time = "2025-06-14T15:14:34.132Z" },
{ url = "https://files.pythonhosted.org/packages/26/7f/32ca0f170496aa2ab9b812630fac0c2372c531b797e1deb3deb4cea904bd/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad7c8e5c25f2a26842a7c239de3f7b6bfb92304593ef997c04ac49fb703ff4d7", size = 1703683, upload-time = "2025-06-14T15:14:36.034Z" },
{ url = "https://files.pythonhosted.org/packages/ec/53/d5513624b33a811c0abea8461e30a732294112318276ce3dbf047dbd9d8b/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6af355b483e3fe9d7336d84539fef460120c2f6e50e06c658fe2907c69262d6b", size = 1684946, upload-time = "2025-06-14T15:14:38Z" },
{ url = "https://files.pythonhosted.org/packages/37/72/4c237dd127827b0247dc138d3ebd49c2ded6114c6991bbe969058575f25f/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a95cf9f097498f35c88e3609f55bb47b28a5ef67f6888f4390b3d73e2bac6177", size = 1737017, upload-time = "2025-06-14T15:14:39.951Z" },
{ url = "https://files.pythonhosted.org/packages/0d/67/8a7eb3afa01e9d0acc26e1ef847c1a9111f8b42b82955fcd9faeb84edeb4/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8ed8c38a1c584fe99a475a8f60eefc0b682ea413a84c6ce769bb19a7ff1c5ef", size = 1786390, upload-time = "2025-06-14T15:14:42.151Z" },
{ url = "https://files.pythonhosted.org/packages/48/19/0377df97dd0176ad23cd8cad4fd4232cfeadcec6c1b7f036315305c98e3f/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0b9170d5d800126b5bc89d3053a2363406d6e327afb6afaeda2d19ee8bb103", size = 1708719, upload-time = "2025-06-14T15:14:44.039Z" },
{ url = "https://files.pythonhosted.org/packages/61/97/ade1982a5c642b45f3622255173e40c3eed289c169f89d00eeac29a89906/aiohttp-3.12.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:372feeace612ef8eb41f05ae014a92121a512bd5067db8f25101dd88a8db11da", size = 1622424, upload-time = "2025-06-14T15:14:45.945Z" },
{ url = "https://files.pythonhosted.org/packages/99/ab/00ad3eea004e1d07ccc406e44cfe2b8da5acb72f8c66aeeb11a096798868/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a946d3702f7965d81f7af7ea8fb03bb33fe53d311df48a46eeca17e9e0beed2d", size = 1675447, upload-time = "2025-06-14T15:14:47.911Z" },
{ url = "https://files.pythonhosted.org/packages/3f/fe/74e5ce8b2ccaba445fe0087abc201bfd7259431d92ae608f684fcac5d143/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a0c4725fae86555bbb1d4082129e21de7264f4ab14baf735278c974785cd2041", size = 1707110, upload-time = "2025-06-14T15:14:50.334Z" },
{ url = "https://files.pythonhosted.org/packages/ef/c4/39af17807f694f7a267bd8ab1fbacf16ad66740862192a6c8abac2bff813/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b28ea2f708234f0a5c44eb6c7d9eb63a148ce3252ba0140d050b091b6e842d1", size = 1649706, upload-time = "2025-06-14T15:14:52.378Z" },
{ url = "https://files.pythonhosted.org/packages/38/e8/f5a0a5f44f19f171d8477059aa5f28a158d7d57fe1a46c553e231f698435/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d4f5becd2a5791829f79608c6f3dc745388162376f310eb9c142c985f9441cc1", size = 1725839, upload-time = "2025-06-14T15:14:54.617Z" },
{ url = "https://files.pythonhosted.org/packages/fd/ac/81acc594c7f529ef4419d3866913f628cd4fa9cab17f7bf410a5c3c04c53/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:60f2ce6b944e97649051d5f5cc0f439360690b73909230e107fd45a359d3e911", size = 1759311, upload-time = "2025-06-14T15:14:56.597Z" },
{ url = "https://files.pythonhosted.org/packages/38/0d/aabe636bd25c6ab7b18825e5a97d40024da75152bec39aa6ac8b7a677630/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69fc1909857401b67bf599c793f2183fbc4804717388b0b888f27f9929aa41f3", size = 1708202, upload-time = "2025-06-14T15:14:58.598Z" },
{ url = "https://files.pythonhosted.org/packages/1f/ab/561ef2d8a223261683fb95a6283ad0d36cb66c87503f3a7dde7afe208bb2/aiohttp-3.12.13-cp313-cp313-win32.whl", hash = "sha256:7d7e68787a2046b0e44ba5587aa723ce05d711e3a3665b6b7545328ac8e3c0dd", size = 420794, upload-time = "2025-06-14T15:15:00.939Z" },
{ url = "https://files.pythonhosted.org/packages/9d/47/b11d0089875a23bff0abd3edb5516bcd454db3fefab8604f5e4b07bd6210/aiohttp-3.12.13-cp313-cp313-win_amd64.whl", hash = "sha256:5a178390ca90419bfd41419a809688c368e63c86bd725e1186dd97f6b89c2706", size = 446735, upload-time = "2025-06-14T15:15:02.858Z" },
]
[[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.3.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "frozenlist" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" },
]
[[package]]
name = "astroid"
version = "3.3.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/00/c2/9b2de9ed027f9fe5734a6c0c0a601289d796b3caaf1e372e23fa88a73047/astroid-3.3.10.tar.gz", hash = "sha256:c332157953060c6deb9caa57303ae0d20b0fbdb2e59b4a4f2a6ba49d0a7961ce", size = 398941, upload-time = "2025-05-10T13:33:10.405Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/15/58/5260205b9968c20b6457ed82f48f9e3d6edf2f1f95103161798b73aeccf0/astroid-3.3.10-py3-none-any.whl", hash = "sha256:104fb9cb9b27ea95e847a94c003be03a9e039334a8ebca5ee27dafaf5c5711eb", size = 275388, upload-time = "2025-05-10T13:33:08.391Z" },
]
[[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.9.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e7/e0/98670a80884f64578f0c22cd70c5e81a6e07b08167721c7487b4d70a7ca0/coverage-7.9.1.tar.gz", hash = "sha256:6cf43c78c4282708a28e466316935ec7489a9c487518a77fa68f716c67909cec", size = 813650, upload-time = "2025-06-13T13:02:28.627Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d0/a7/a027970c991ca90f24e968999f7d509332daf6b8c3533d68633930aaebac/coverage-7.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:31324f18d5969feef7344a932c32428a2d1a3e50b15a6404e97cba1cc9b2c631", size = 212358, upload-time = "2025-06-13T13:01:30.909Z" },
{ url = "https://files.pythonhosted.org/packages/f2/48/6aaed3651ae83b231556750280682528fea8ac7f1232834573472d83e459/coverage-7.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0c804506d624e8a20fb3108764c52e0eef664e29d21692afa375e0dd98dc384f", size = 212620, upload-time = "2025-06-13T13:01:32.256Z" },
{ url = "https://files.pythonhosted.org/packages/6c/2a/f4b613f3b44d8b9f144847c89151992b2b6b79cbc506dee89ad0c35f209d/coverage-7.9.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef64c27bc40189f36fcc50c3fb8f16ccda73b6a0b80d9bd6e6ce4cffcd810bbd", size = 245788, upload-time = "2025-06-13T13:01:33.948Z" },
{ url = "https://files.pythonhosted.org/packages/04/d2/de4fdc03af5e4e035ef420ed26a703c6ad3d7a07aff2e959eb84e3b19ca8/coverage-7.9.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4fe2348cc6ec372e25adec0219ee2334a68d2f5222e0cba9c0d613394e12d86", size = 243001, upload-time = "2025-06-13T13:01:35.285Z" },
{ url = "https://files.pythonhosted.org/packages/f5/e8/eed18aa5583b0423ab7f04e34659e51101135c41cd1dcb33ac1d7013a6d6/coverage-7.9.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34ed2186fe52fcc24d4561041979a0dec69adae7bce2ae8d1c49eace13e55c43", size = 244985, upload-time = "2025-06-13T13:01:36.712Z" },
{ url = "https://files.pythonhosted.org/packages/17/f8/ae9e5cce8885728c934eaa58ebfa8281d488ef2afa81c3dbc8ee9e6d80db/coverage-7.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:25308bd3d00d5eedd5ae7d4357161f4df743e3c0240fa773ee1b0f75e6c7c0f1", size = 245152, upload-time = "2025-06-13T13:01:39.303Z" },
{ url = "https://files.pythonhosted.org/packages/5a/c8/272c01ae792bb3af9b30fac14d71d63371db227980682836ec388e2c57c0/coverage-7.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73e9439310f65d55a5a1e0564b48e34f5369bee943d72c88378f2d576f5a5751", size = 243123, upload-time = "2025-06-13T13:01:40.727Z" },
{ url = "https://files.pythonhosted.org/packages/8c/d0/2819a1e3086143c094ab446e3bdf07138527a7b88cb235c488e78150ba7a/coverage-7.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37ab6be0859141b53aa89412a82454b482c81cf750de4f29223d52268a86de67", size = 244506, upload-time = "2025-06-13T13:01:42.184Z" },
{ url = "https://files.pythonhosted.org/packages/8b/4e/9f6117b89152df7b6112f65c7a4ed1f2f5ec8e60c4be8f351d91e7acc848/coverage-7.9.1-cp313-cp313-win32.whl", hash = "sha256:64bdd969456e2d02a8b08aa047a92d269c7ac1f47e0c977675d550c9a0863643", size = 214766, upload-time = "2025-06-13T13:01:44.482Z" },
{ url = "https://files.pythonhosted.org/packages/27/0f/4b59f7c93b52c2c4ce7387c5a4e135e49891bb3b7408dcc98fe44033bbe0/coverage-7.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:be9e3f68ca9edb897c2184ad0eee815c635565dbe7a0e7e814dc1f7cbab92c0a", size = 215568, upload-time = "2025-06-13T13:01:45.772Z" },
{ url = "https://files.pythonhosted.org/packages/09/1e/9679826336f8c67b9c39a359352882b24a8a7aee48d4c9cad08d38d7510f/coverage-7.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:1c503289ffef1d5105d91bbb4d62cbe4b14bec4d13ca225f9c73cde9bb46207d", size = 213939, upload-time = "2025-06-13T13:01:47.087Z" },
{ url = "https://files.pythonhosted.org/packages/bb/5b/5c6b4e7a407359a2e3b27bf9c8a7b658127975def62077d441b93a30dbe8/coverage-7.9.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0b3496922cb5f4215bf5caaef4cf12364a26b0be82e9ed6d050f3352cf2d7ef0", size = 213079, upload-time = "2025-06-13T13:01:48.554Z" },
{ url = "https://files.pythonhosted.org/packages/a2/22/1e2e07279fd2fd97ae26c01cc2186e2258850e9ec125ae87184225662e89/coverage-7.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9565c3ab1c93310569ec0d86b017f128f027cab0b622b7af288696d7ed43a16d", size = 213299, upload-time = "2025-06-13T13:01:49.997Z" },
{ url = "https://files.pythonhosted.org/packages/14/c0/4c5125a4b69d66b8c85986d3321520f628756cf524af810baab0790c7647/coverage-7.9.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2241ad5dbf79ae1d9c08fe52b36d03ca122fb9ac6bca0f34439e99f8327ac89f", size = 256535, upload-time = "2025-06-13T13:01:51.314Z" },
{ url = "https://files.pythonhosted.org/packages/81/8b/e36a04889dda9960be4263e95e777e7b46f1bb4fc32202612c130a20c4da/coverage-7.9.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bb5838701ca68b10ebc0937dbd0eb81974bac54447c55cd58dea5bca8451029", size = 252756, upload-time = "2025-06-13T13:01:54.403Z" },
{ url = "https://files.pythonhosted.org/packages/98/82/be04eff8083a09a4622ecd0e1f31a2c563dbea3ed848069e7b0445043a70/coverage-7.9.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a25f814591a8c0c5372c11ac8967f669b97444c47fd794926e175c4047ece", size = 254912, upload-time = "2025-06-13T13:01:56.769Z" },
{ url = "https://files.pythonhosted.org/packages/0f/25/c26610a2c7f018508a5ab958e5b3202d900422cf7cdca7670b6b8ca4e8df/coverage-7.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2d04b16a6062516df97969f1ae7efd0de9c31eb6ebdceaa0d213b21c0ca1a683", size = 256144, upload-time = "2025-06-13T13:01:58.19Z" },
{ url = "https://files.pythonhosted.org/packages/c5/8b/fb9425c4684066c79e863f1e6e7ecebb49e3a64d9f7f7860ef1688c56f4a/coverage-7.9.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7931b9e249edefb07cd6ae10c702788546341d5fe44db5b6108a25da4dca513f", size = 254257, upload-time = "2025-06-13T13:01:59.645Z" },
{ url = "https://files.pythonhosted.org/packages/93/df/27b882f54157fc1131e0e215b0da3b8d608d9b8ef79a045280118a8f98fe/coverage-7.9.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52e92b01041151bf607ee858e5a56c62d4b70f4dac85b8c8cb7fb8a351ab2c10", size = 255094, upload-time = "2025-06-13T13:02:01.37Z" },
{ url = "https://files.pythonhosted.org/packages/41/5f/cad1c3dbed8b3ee9e16fa832afe365b4e3eeab1fb6edb65ebbf745eabc92/coverage-7.9.1-cp313-cp313t-win32.whl", hash = "sha256:684e2110ed84fd1ca5f40e89aa44adf1729dc85444004111aa01866507adf363", size = 215437, upload-time = "2025-06-13T13:02:02.905Z" },
{ url = "https://files.pythonhosted.org/packages/99/4d/fad293bf081c0e43331ca745ff63673badc20afea2104b431cdd8c278b4c/coverage-7.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:437c576979e4db840539674e68c84b3cda82bc824dd138d56bead1435f1cb5d7", size = 216605, upload-time = "2025-06-13T13:02:05.638Z" },
{ url = "https://files.pythonhosted.org/packages/1f/56/4ee027d5965fc7fc126d7ec1187529cc30cc7d740846e1ecb5e92d31b224/coverage-7.9.1-cp313-cp313t-win_arm64.whl", hash = "sha256:18a0912944d70aaf5f399e350445738a1a20b50fbea788f640751c2ed9208b6c", size = 214392, upload-time = "2025-06-13T13:02:07.642Z" },
{ url = "https://files.pythonhosted.org/packages/08/b8/7ddd1e8ba9701dea08ce22029917140e6f66a859427406579fd8d0ca7274/coverage-7.9.1-py3-none-any.whl", hash = "sha256:66b974b145aa189516b6bf2d8423e888b742517d37872f6ee4c5be0073bd9a3c", size = 204000, upload-time = "2025-06-13T13:02:27.173Z" },
]
[[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.3.9"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" },
]
[[package]]
name = "filelock"
version = "3.18.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" },
]
[[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.12"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" },
]
[[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.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/46/b5/59f27b4ce9951a4bce56b88ba5ff5159486797ab18863f2b4c1c5e8465bd/multidict-6.5.0.tar.gz", hash = "sha256:942bd8002492ba819426a8d7aefde3189c1b87099cdf18aaaefefcf7f3f7b6d2", size = 98512, upload-time = "2025-06-17T14:15:56.556Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1a/c9/092c4e9402b6d16de761cff88cb842a5c8cc50ccecaf9c4481ba53264b9e/multidict-6.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:53d92df1752df67a928fa7f884aa51edae6f1cf00eeb38cbcf318cf841c17456", size = 73486, upload-time = "2025-06-17T14:14:37.238Z" },
{ url = "https://files.pythonhosted.org/packages/08/f9/6f7ddb8213f5fdf4db48d1d640b78e8aef89b63a5de8a2313286db709250/multidict-6.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:680210de2c38eef17ce46b8df8bf2c1ece489261a14a6e43c997d49843a27c99", size = 43745, upload-time = "2025-06-17T14:14:38.32Z" },
{ url = "https://files.pythonhosted.org/packages/f3/a7/b9be0163bfeee3bb08a77a1705e24eb7e651d594ea554107fac8a1ca6a4d/multidict-6.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e279259bcb936732bfa1a8eec82b5d2352b3df69d2fa90d25808cfc403cee90a", size = 42135, upload-time = "2025-06-17T14:14:39.897Z" },
{ url = "https://files.pythonhosted.org/packages/8e/30/93c8203f943a417bda3c573a34d5db0cf733afdfffb0ca78545c7716dbd8/multidict-6.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1c185fc1069781e3fc8b622c4331fb3b433979850392daa5efbb97f7f9959bb", size = 238585, upload-time = "2025-06-17T14:14:41.332Z" },
{ url = "https://files.pythonhosted.org/packages/9d/fe/2582b56a1807604774f566eeef183b0d6b148f4b89d1612cd077567b2e1e/multidict-6.5.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6bb5f65ff91daf19ce97f48f63585e51595539a8a523258b34f7cef2ec7e0617", size = 236174, upload-time = "2025-06-17T14:14:42.602Z" },
{ url = "https://files.pythonhosted.org/packages/9b/c4/d8b66d42d385bd4f974cbd1eaa8b265e6b8d297249009f312081d5ded5c7/multidict-6.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8646b4259450c59b9286db280dd57745897897284f6308edbdf437166d93855", size = 250145, upload-time = "2025-06-17T14:14:43.944Z" },
{ url = "https://files.pythonhosted.org/packages/bc/64/62feda5093ee852426aae3df86fab079f8bf1cdbe403e1078c94672ad3ec/multidict-6.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d245973d4ecc04eea0a8e5ebec7882cf515480036e1b48e65dffcfbdf86d00be", size = 243470, upload-time = "2025-06-17T14:14:45.343Z" },
{ url = "https://files.pythonhosted.org/packages/67/dc/9f6fa6e854625cf289c0e9f4464b40212a01f76b2f3edfe89b6779b4fb93/multidict-6.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a133e7ddc9bc7fb053733d0ff697ce78c7bf39b5aec4ac12857b6116324c8d75", size = 236968, upload-time = "2025-06-17T14:14:46.609Z" },
{ url = "https://files.pythonhosted.org/packages/46/ae/4b81c6e3745faee81a156f3f87402315bdccf04236f75c03e37be19c94ff/multidict-6.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80d696fa38d738fcebfd53eec4d2e3aeb86a67679fd5e53c325756682f152826", size = 236575, upload-time = "2025-06-17T14:14:47.929Z" },
{ url = "https://files.pythonhosted.org/packages/8a/fa/4089d7642ea344226e1bfab60dd588761d4791754f8072e911836a39bedf/multidict-6.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:20d30c9410ac3908abbaa52ee5967a754c62142043cf2ba091e39681bd51d21a", size = 247632, upload-time = "2025-06-17T14:14:49.525Z" },
{ url = "https://files.pythonhosted.org/packages/16/ee/a353dac797de0f28fb7f078cc181c5f2eefe8dd16aa11a7100cbdc234037/multidict-6.5.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6c65068cc026f217e815fa519d8e959a7188e94ec163ffa029c94ca3ef9d4a73", size = 243520, upload-time = "2025-06-17T14:14:50.83Z" },
{ url = "https://files.pythonhosted.org/packages/50/ec/560deb3d2d95822d6eb1bcb1f1cb728f8f0197ec25be7c936d5d6a5d133c/multidict-6.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e355ac668a8c3e49c2ca8daa4c92f0ad5b705d26da3d5af6f7d971e46c096da7", size = 248551, upload-time = "2025-06-17T14:14:52.229Z" },
{ url = "https://files.pythonhosted.org/packages/10/85/ddf277e67c78205f6695f2a7639be459bca9cc353b962fd8085a492a262f/multidict-6.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:08db204213d0375a91a381cae0677ab95dd8c67a465eb370549daf6dbbf8ba10", size = 258362, upload-time = "2025-06-17T14:14:53.934Z" },
{ url = "https://files.pythonhosted.org/packages/02/fc/d64ee1df9b87c5210f2d4c419cab07f28589c81b4e5711eda05a122d0614/multidict-6.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ffa58e3e215af8f6536dc837a990e456129857bb6fd546b3991be470abd9597a", size = 253862, upload-time = "2025-06-17T14:14:55.323Z" },
{ url = "https://files.pythonhosted.org/packages/c9/7c/a2743c00d9e25f4826d3a77cc13d4746398872cf21c843eef96bb9945665/multidict-6.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e86eb90015c6f21658dbd257bb8e6aa18bdb365b92dd1fba27ec04e58cdc31b", size = 247391, upload-time = "2025-06-17T14:14:57.293Z" },
{ url = "https://files.pythonhosted.org/packages/9b/03/7773518db74c442904dbd349074f1e7f2a854cee4d9529fc59e623d3949e/multidict-6.5.0-cp313-cp313-win32.whl", hash = "sha256:f34a90fbd9959d0f857323bd3c52b3e6011ed48f78d7d7b9e04980b8a41da3af", size = 41115, upload-time = "2025-06-17T14:14:59.33Z" },
{ url = "https://files.pythonhosted.org/packages/eb/9a/6fc51b1dc11a7baa944bc101a92167d8b0f5929d376a8c65168fc0d35917/multidict-6.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:fcb2aa79ac6aef8d5b709bbfc2fdb1d75210ba43038d70fbb595b35af470ce06", size = 44768, upload-time = "2025-06-17T14:15:00.427Z" },
{ url = "https://files.pythonhosted.org/packages/82/2d/0d010be24b663b3c16e3d3307bbba2de5ae8eec496f6027d5c0515b371a8/multidict-6.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:6dcee5e7e92060b4bb9bb6f01efcbb78c13d0e17d9bc6eec71660dd71dc7b0c2", size = 41770, upload-time = "2025-06-17T14:15:01.854Z" },
{ url = "https://files.pythonhosted.org/packages/aa/d1/a71711a5f32f84b7b036e82182e3250b949a0ce70d51a2c6a4079e665449/multidict-6.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:cbbc88abea2388fde41dd574159dec2cda005cb61aa84950828610cb5010f21a", size = 80450, upload-time = "2025-06-17T14:15:02.968Z" },
{ url = "https://files.pythonhosted.org/packages/0f/a2/953a9eede63a98fcec2c1a2c1a0d88de120056219931013b871884f51b43/multidict-6.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70b599f70ae6536e5976364d3c3cf36f40334708bd6cebdd1e2438395d5e7676", size = 46971, upload-time = "2025-06-17T14:15:04.149Z" },
{ url = "https://files.pythonhosted.org/packages/44/61/60250212953459edda2c729e1d85130912f23c67bd4f585546fe4bdb1578/multidict-6.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:828bab777aa8d29d59700018178061854e3a47727e0611cb9bec579d3882de3b", size = 45548, upload-time = "2025-06-17T14:15:05.666Z" },
{ url = "https://files.pythonhosted.org/packages/11/b6/e78ee82e96c495bc2582b303f68bed176b481c8d81a441fec07404fce2ca/multidict-6.5.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9695fc1462f17b131c111cf0856a22ff154b0480f86f539d24b2778571ff94d", size = 238545, upload-time = "2025-06-17T14:15:06.88Z" },
{ url = "https://files.pythonhosted.org/packages/5a/0f/6132ca06670c8d7b374c3a4fd1ba896fc37fbb66b0de903f61db7d1020ec/multidict-6.5.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b5ac6ebaf5d9814b15f399337ebc6d3a7f4ce9331edd404e76c49a01620b68d", size = 229931, upload-time = "2025-06-17T14:15:08.24Z" },
{ url = "https://files.pythonhosted.org/packages/c0/63/d9957c506e6df6b3e7a194f0eea62955c12875e454b978f18262a65d017b/multidict-6.5.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84a51e3baa77ded07be4766a9e41d977987b97e49884d4c94f6d30ab6acaee14", size = 248181, upload-time = "2025-06-17T14:15:09.907Z" },
{ url = "https://files.pythonhosted.org/packages/43/3f/7d5490579640db5999a948e2c41d4a0efd91a75989bda3e0a03a79c92be2/multidict-6.5.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8de67f79314d24179e9b1869ed15e88d6ba5452a73fc9891ac142e0ee018b5d6", size = 241846, upload-time = "2025-06-17T14:15:11.596Z" },
{ url = "https://files.pythonhosted.org/packages/e1/f7/252b1ce949ece52bba4c0de7aa2e3a3d5964e800bce71fb778c2e6c66f7c/multidict-6.5.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17f78a52c214481d30550ec18208e287dfc4736f0c0148208334b105fd9e0887", size = 232893, upload-time = "2025-06-17T14:15:12.946Z" },
{ url = "https://files.pythonhosted.org/packages/45/7e/0070bfd48c16afc26e056f2acce49e853c0d604a69c7124bc0bbdb1bcc0a/multidict-6.5.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2966d0099cb2e2039f9b0e73e7fd5eb9c85805681aa2a7f867f9d95b35356921", size = 228567, upload-time = "2025-06-17T14:15:14.267Z" },
{ url = "https://files.pythonhosted.org/packages/2a/31/90551c75322113ebf5fd9c5422e8641d6952f6edaf6b6c07fdc49b1bebdd/multidict-6.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:86fb42ed5ed1971c642cc52acc82491af97567534a8e381a8d50c02169c4e684", size = 246188, upload-time = "2025-06-17T14:15:15.985Z" },
{ url = "https://files.pythonhosted.org/packages/cc/e2/aa4b02a55e7767ff292871023817fe4db83668d514dab7ccbce25eaf7659/multidict-6.5.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:4e990cbcb6382f9eae4ec720bcac6a1351509e6fc4a5bb70e4984b27973934e6", size = 235178, upload-time = "2025-06-17T14:15:17.395Z" },
{ url = "https://files.pythonhosted.org/packages/7d/5c/f67e726717c4b138b166be1700e2b56e06fbbcb84643d15f9a9d7335ff41/multidict-6.5.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d99a59d64bb1f7f2117bec837d9e534c5aeb5dcedf4c2b16b9753ed28fdc20a3", size = 243422, upload-time = "2025-06-17T14:15:18.939Z" },
{ url = "https://files.pythonhosted.org/packages/e5/1c/15fa318285e26a50aa3fa979bbcffb90f9b4d5ec58882d0590eda067d0da/multidict-6.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:e8ef15cc97c9890212e1caf90f0d63f6560e1e101cf83aeaf63a57556689fb34", size = 254898, upload-time = "2025-06-17T14:15:20.31Z" },
{ url = "https://files.pythonhosted.org/packages/ad/3d/d6c6d1c2e9b61ca80313912d30bb90d4179335405e421ef0a164eac2c0f9/multidict-6.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:b8a09aec921b34bd8b9f842f0bcfd76c6a8c033dc5773511e15f2d517e7e1068", size = 247129, upload-time = "2025-06-17T14:15:21.665Z" },
{ url = "https://files.pythonhosted.org/packages/29/15/1568258cf0090bfa78d44be66247cfdb16e27dfd935c8136a1e8632d3057/multidict-6.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ff07b504c23b67f2044533244c230808a1258b3493aaf3ea2a0785f70b7be461", size = 243841, upload-time = "2025-06-17T14:15:23.38Z" },
{ url = "https://files.pythonhosted.org/packages/65/57/64af5dbcfd61427056e840c8e520b502879d480f9632fbe210929fd87393/multidict-6.5.0-cp313-cp313t-win32.whl", hash = "sha256:9232a117341e7e979d210e41c04e18f1dc3a1d251268df6c818f5334301274e1", size = 46761, upload-time = "2025-06-17T14:15:24.733Z" },
{ url = "https://files.pythonhosted.org/packages/26/a8/cac7f7d61e188ff44f28e46cb98f9cc21762e671c96e031f06c84a60556e/multidict-6.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:44cb5c53fb2d4cbcee70a768d796052b75d89b827643788a75ea68189f0980a1", size = 52112, upload-time = "2025-06-17T14:15:25.906Z" },
{ url = "https://files.pythonhosted.org/packages/51/9f/076533feb1b5488d22936da98b9c217205cfbf9f56f7174e8c5c86d86fe6/multidict-6.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:51d33fafa82640c0217391d4ce895d32b7e84a832b8aee0dcc1b04d8981ec7f4", size = 44358, upload-time = "2025-06-17T14:15:27.117Z" },
{ url = "https://files.pythonhosted.org/packages/44/d8/45e8fc9892a7386d074941429e033adb4640e59ff0780d96a8cf46fe788e/multidict-6.5.0-py3-none-any.whl", hash = "sha256:5634b35f225977605385f56153bd95a7133faffc0ffe12ad26e10517537e8dfc", size = 12181, upload-time = "2025-06-17T14:15:55.156Z" },
]
[[package]]
name = "mypy"
version = "1.16.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "pathspec" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/81/69/92c7fa98112e4d9eb075a239caa4ef4649ad7d441545ccffbd5e34607cbb/mypy-1.16.1.tar.gz", hash = "sha256:6bd00a0a2094841c5e47e7374bb42b83d64c527a502e3334e1173a0c24437bab", size = 3324747, upload-time = "2025-06-16T16:51:35.145Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/28/e3/96964af4a75a949e67df4b95318fe2b7427ac8189bbc3ef28f92a1c5bc56/mypy-1.16.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ddc91eb318c8751c69ddb200a5937f1232ee8efb4e64e9f4bc475a33719de438", size = 11063480, upload-time = "2025-06-16T16:47:56.205Z" },
{ url = "https://files.pythonhosted.org/packages/f5/4d/cd1a42b8e5be278fab7010fb289d9307a63e07153f0ae1510a3d7b703193/mypy-1.16.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:87ff2c13d58bdc4bbe7dc0dedfe622c0f04e2cb2a492269f3b418df2de05c536", size = 10090538, upload-time = "2025-06-16T16:46:43.92Z" },
{ url = "https://files.pythonhosted.org/packages/c9/4f/c3c6b4b66374b5f68bab07c8cabd63a049ff69796b844bc759a0ca99bb2a/mypy-1.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a7cfb0fe29fe5a9841b7c8ee6dffb52382c45acdf68f032145b75620acfbd6f", size = 11836839, upload-time = "2025-06-16T16:36:28.039Z" },
{ url = "https://files.pythonhosted.org/packages/b4/7e/81ca3b074021ad9775e5cb97ebe0089c0f13684b066a750b7dc208438403/mypy-1.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:051e1677689c9d9578b9c7f4d206d763f9bbd95723cd1416fad50db49d52f359", size = 12715634, upload-time = "2025-06-16T16:50:34.441Z" },
{ url = "https://files.pythonhosted.org/packages/e9/95/bdd40c8be346fa4c70edb4081d727a54d0a05382d84966869738cfa8a497/mypy-1.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d5d2309511cc56c021b4b4e462907c2b12f669b2dbeb68300110ec27723971be", size = 12895584, upload-time = "2025-06-16T16:34:54.857Z" },
{ url = "https://files.pythonhosted.org/packages/5a/fd/d486a0827a1c597b3b48b1bdef47228a6e9ee8102ab8c28f944cb83b65dc/mypy-1.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee", size = 9573886, upload-time = "2025-06-16T16:36:43.589Z" },
{ url = "https://files.pythonhosted.org/packages/cf/d3/53e684e78e07c1a2bf7105715e5edd09ce951fc3f47cf9ed095ec1b7a037/mypy-1.16.1-py3-none-any.whl", hash = "sha256:5fc2ac4027d0ef28d6ba69a0343737a23c4d1b83672bf38d1fe237bdc0643b37", size = 2265923, upload-time = "2025-06-16T16:48:02.366Z" },
]
[[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.2.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/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" },
]
[[package]]
name = "pre-commit-hooks"
version = "5.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ruamel-yaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ac/7d/3299241a753c738d114600c360d754550b28c285281dc6a5132c4ccfae65/pre_commit_hooks-5.0.0.tar.gz", hash = "sha256:10626959a9eaf602fbfc22bc61b6e75801436f82326bfcee82bb1f2fc4bc646e", size = 29747, upload-time = "2024-10-05T18:43:11.225Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/29/db1d855a661c02dbde5cab3057969133fcc62e7a0c6393e48fe9d0e81679/pre_commit_hooks-5.0.0-py2.py3-none-any.whl", hash = "sha256:8d71cfb582c5c314a5498d94e0104b6567a8b93fb35903ea845c491f4e290a7a", size = 41245, upload-time = "2024-10-05T18:43:09.901Z" },
]
[[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.7"
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/1c/e4/83e487d3ddd64ab27749b66137b26dc0c5b5c161be680e6beffdc99070b3/pylint-3.3.7.tar.gz", hash = "sha256:2b11de8bde49f9c5059452e0c310c079c746a0a8eeaa789e5aa966ecc23e4559", size = 1520709, upload-time = "2025-05-04T17:07:51.089Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e8/83/bff755d09e31b5d25cc7fdc4bf3915d1a404e181f1abf0359af376845c24/pylint-3.3.7-py3-none-any.whl", hash = "sha256:43860aafefce92fca4cf6b61fe199cdc5ae54ea28f9bf4cd49de267b5195803d", size = 522565, upload-time = "2025-05-04T17:07:48.714Z" },
]
[[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.13" },
{ 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.9.1" },
{ name = "mypy", specifier = ">=1.16.1" },
{ name = "pre-commit", specifier = ">=4.2.0" },
{ name = "pre-commit-hooks", specifier = ">=5.0.0" },
{ name = "pylint", specifier = ">=3.3.7" },
{ name = "pytest", specifier = ">=8.4.1" },
{ name = "pytest-aiohttp", specifier = ">=1.1.0" },
{ name = "pytest-asyncio", specifier = ">=1.0.0" },
{ name = "pytest-cov", specifier = ">=6.2.1" },
{ name = "ruff", specifier = ">=0.12.0" },
{ 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.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d0/d4/14f53324cb1a6381bef29d698987625d80052bb33932d8e7cbf9b337b17c/pytest_asyncio-1.0.0.tar.gz", hash = "sha256:d15463d13f4456e1ead2594520216b225a16f781e144f8fdf6c5bb4667c48b3f", size = 46960, upload-time = "2025-05-26T04:54:40.484Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/30/05/ce271016e351fddc8399e546f6e23761967ee09c8c568bbfbecb0c150171/pytest_asyncio-1.0.0-py3-none-any.whl", hash = "sha256:4f024da9f1ef945e680dc68610b52550e36590a67fd31bb3b4943979a1f90ef3", size = 15976, upload-time = "2025-05-26T04:54:39.035Z" },
]
[[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.14"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ruamel-yaml-clib", marker = "python_full_version < '3.14' and platform_python_implementation == 'CPython'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/39/87/6da0df742a4684263261c253f00edd5829e6aca970fff69e75028cccc547/ruamel.yaml-0.18.14.tar.gz", hash = "sha256:7227b76aaec364df15936730efbf7d72b30c0b79b1d578bbb8e3dcb2d81f52b7", size = 145511, upload-time = "2025-06-09T08:51:09.828Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/af/6d/6fe4805235e193aad4aaf979160dd1f3c487c57d48b810c816e6e842171b/ruamel.yaml-0.18.14-py3-none-any.whl", hash = "sha256:710ff198bb53da66718c7db27eec4fbcc9aa6ca7204e4c1df2f282b6fe5eb6b2", size = 118570, upload-time = "2025-06-09T08:51:06.348Z" },
]
[[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.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/24/90/5255432602c0b196a0da6720f6f76b93eb50baef46d3c9b0025e2f9acbf3/ruff-0.12.0.tar.gz", hash = "sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c", size = 4376101, upload-time = "2025-06-17T15:19:26.217Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e6/fd/b46bb20e14b11ff49dbc74c61de352e0dc07fb650189513631f6fb5fc69f/ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848", size = 10311554, upload-time = "2025-06-17T15:18:45.792Z" },
{ url = "https://files.pythonhosted.org/packages/e7/d3/021dde5a988fa3e25d2468d1dadeea0ae89dc4bc67d0140c6e68818a12a1/ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6", size = 11118435, upload-time = "2025-06-17T15:18:49.064Z" },
{ url = "https://files.pythonhosted.org/packages/07/a2/01a5acf495265c667686ec418f19fd5c32bcc326d4c79ac28824aecd6a32/ruff-0.12.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0", size = 10466010, upload-time = "2025-06-17T15:18:51.341Z" },
{ url = "https://files.pythonhosted.org/packages/4c/57/7caf31dd947d72e7aa06c60ecb19c135cad871a0a8a251723088132ce801/ruff-0.12.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48", size = 10661366, upload-time = "2025-06-17T15:18:53.29Z" },
{ url = "https://files.pythonhosted.org/packages/e9/ba/aa393b972a782b4bc9ea121e0e358a18981980856190d7d2b6187f63e03a/ruff-0.12.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807", size = 10173492, upload-time = "2025-06-17T15:18:55.262Z" },
{ url = "https://files.pythonhosted.org/packages/d7/50/9349ee777614bc3062fc6b038503a59b2034d09dd259daf8192f56c06720/ruff-0.12.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82", size = 11761739, upload-time = "2025-06-17T15:18:58.906Z" },
{ url = "https://files.pythonhosted.org/packages/04/8f/ad459de67c70ec112e2ba7206841c8f4eb340a03ee6a5cabc159fe558b8e/ruff-0.12.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c", size = 12537098, upload-time = "2025-06-17T15:19:01.316Z" },
{ url = "https://files.pythonhosted.org/packages/ed/50/15ad9c80ebd3c4819f5bd8883e57329f538704ed57bac680d95cb6627527/ruff-0.12.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165", size = 12154122, upload-time = "2025-06-17T15:19:03.727Z" },
{ url = "https://files.pythonhosted.org/packages/76/e6/79b91e41bc8cc3e78ee95c87093c6cacfa275c786e53c9b11b9358026b3d/ruff-0.12.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2", size = 11363374, upload-time = "2025-06-17T15:19:05.875Z" },
{ url = "https://files.pythonhosted.org/packages/db/c3/82b292ff8a561850934549aa9dc39e2c4e783ab3c21debe55a495ddf7827/ruff-0.12.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4", size = 11587647, upload-time = "2025-06-17T15:19:08.246Z" },
{ url = "https://files.pythonhosted.org/packages/2b/42/d5760d742669f285909de1bbf50289baccb647b53e99b8a3b4f7ce1b2001/ruff-0.12.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514", size = 10527284, upload-time = "2025-06-17T15:19:10.37Z" },
{ url = "https://files.pythonhosted.org/packages/19/f6/fcee9935f25a8a8bba4adbae62495c39ef281256693962c2159e8b284c5f/ruff-0.12.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88", size = 10158609, upload-time = "2025-06-17T15:19:12.286Z" },
{ url = "https://files.pythonhosted.org/packages/37/fb/057febf0eea07b9384787bfe197e8b3384aa05faa0d6bd844b94ceb29945/ruff-0.12.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51", size = 11141462, upload-time = "2025-06-17T15:19:15.195Z" },
{ url = "https://files.pythonhosted.org/packages/10/7c/1be8571011585914b9d23c95b15d07eec2d2303e94a03df58294bc9274d4/ruff-0.12.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a", size = 11641616, upload-time = "2025-06-17T15:19:17.6Z" },
{ url = "https://files.pythonhosted.org/packages/6a/ef/b960ab4818f90ff59e571d03c3f992828d4683561095e80f9ef31f3d58b7/ruff-0.12.0-py3-none-win32.whl", hash = "sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb", size = 10525289, upload-time = "2025-06-17T15:19:19.688Z" },
{ url = "https://files.pythonhosted.org/packages/34/93/8b16034d493ef958a500f17cda3496c63a537ce9d5a6479feec9558f1695/ruff-0.12.0-py3-none-win_amd64.whl", hash = "sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0", size = 11598311, upload-time = "2025-06-17T15:19:21.785Z" },
{ url = "https://files.pythonhosted.org/packages/d0/33/4d3e79e4a84533d6cd526bfb42c020a23256ae5e4265d858bd1287831f7d/ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b", size = 10724946, upload-time = "2025-06-17T15:19:23.952Z" },
]
[[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.14.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" },
]
[[package]]
name = "virtualenv"
version = "20.31.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
{ name = "filelock" },
{ name = "platformdirs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c3a104fd0c495184c4f2336d65baf398e3c75d72ea94/virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af", size = 6076316, upload-time = "2025-05-08T17:58:23.811Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" },
]
[[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" },
]