pax_global_header00006660000000000000000000000064150257662130014521gustar00rootroot0000000000000052 comment=79953284e6337c31b73ca5f811be19f913669dcc paperless-api-4.1.1/000077500000000000000000000000001502576621300142715ustar00rootroot00000000000000paperless-api-4.1.1/.devcontainer/000077500000000000000000000000001502576621300170305ustar00rootroot00000000000000paperless-api-4.1.1/.devcontainer/devcontainer.json000066400000000000000000000036741502576621300224160ustar00rootroot00000000000000{ "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/.editorconfig000066400000000000000000000002741502576621300167510ustar00rootroot00000000000000root = 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/.gitattributes000066400000000000000000000000511502576621300171600ustar00rootroot00000000000000* text eol=lf *.py whitespace=error paperless-api-4.1.1/.github/000077500000000000000000000000001502576621300156315ustar00rootroot00000000000000paperless-api-4.1.1/.github/labels.yml000066400000000000000000000054451502576621300176260ustar00rootroot00000000000000--- - 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.yml000066400000000000000000000020071502576621300214200ustar00rootroot00000000000000--- 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.json000066400000000000000000000021711502576621300203500ustar00rootroot00000000000000{ "$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/000077500000000000000000000000001502576621300176665ustar00rootroot00000000000000paperless-api-4.1.1/.github/workflows/labels.yml000066400000000000000000000007341502576621300216570ustar00rootroot00000000000000--- 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.yml000066400000000000000000000043551502576621300220640ustar00rootroot00000000000000--- 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.yml000066400000000000000000000006651502576621300213500ustar00rootroot00000000000000--- 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.yml000066400000000000000000000014121502576621300222700ustar00rootroot00000000000000--- 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.yml000066400000000000000000000005721502576621300234620ustar00rootroot00000000000000--- 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.yml000066400000000000000000000027331502576621300220360ustar00rootroot00000000000000--- 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.yml000066400000000000000000000025521502576621300215250ustar00rootroot00000000000000--- 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.yml000066400000000000000000000033161502576621300215560ustar00rootroot00000000000000--- 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.yml000066400000000000000000000017101502576621300217220ustar00rootroot00000000000000--- 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/.gitignore000066400000000000000000000027151502576621300162660ustar00rootroot00000000000000# 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.yaml000066400000000000000000000074621502576621300205630ustar00rootroot00000000000000--- 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/000077500000000000000000000000001502576621300156325ustar00rootroot00000000000000paperless-api-4.1.1/.vscode/launch.json000066400000000000000000000004621502576621300200010ustar00rootroot00000000000000{ "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/.yamllint000066400000000000000000000024001502576621300161170ustar00rootroot00000000000000--- 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.dev000066400000000000000000000023711502576621300170430ustar00rootroot00000000000000FROM 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.md000066400000000000000000000020561502576621300157000ustar00rootroot00000000000000# 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.md000066400000000000000000000052751502576621300155610ustar00rootroot00000000000000# 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/000077500000000000000000000000001502576621300152215ustar00rootroot00000000000000paperless-api-4.1.1/docs/usage.md000066400000000000000000000560601502576621300166560ustar00rootroot00000000000000# 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/000077500000000000000000000000001502576621300166405ustar00rootroot00000000000000paperless-api-4.1.1/pypaperless/__init__.py000066400000000000000000000001111502576621300207420ustar00rootroot00000000000000"""PyPaperless.""" from .api import Paperless __all__ = ("Paperless",) paperless-api-4.1.1/pypaperless/api.py000066400000000000000000000341301502576621300177640ustar00rootroot00000000000000"""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.py000066400000000000000000000100631502576621300203400ustar00rootroot00000000000000"""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.py000066400000000000000000000056761502576621300214110ustar00rootroot00000000000000"""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.py000066400000000000000000000020051502576621300206510ustar00rootroot00000000000000"""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/000077500000000000000000000000001502576621300201235ustar00rootroot00000000000000paperless-api-4.1.1/pypaperless/models/__init__.py000066400000000000000000000025361502576621300222420ustar00rootroot00000000000000"""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.py000066400000000000000000000102311502576621300214040ustar00rootroot00000000000000"""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.py000066400000000000000000000151561502576621300230140ustar00rootroot00000000000000"""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.py000066400000000000000000000226471502576621300220000ustar00rootroot00000000000000"""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.py000066400000000000000000000036751502576621300217550ustar00rootroot00000000000000"""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.py000066400000000000000000000034301502576621300233350ustar00rootroot00000000000000"""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.py000066400000000000000000000554231502576621300225070ustar00rootroot00000000000000"""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/000077500000000000000000000000001502576621300222745ustar00rootroot00000000000000paperless-api-4.1.1/pypaperless/models/generators/__init__.py000066400000000000000000000001351502576621300244040ustar00rootroot00000000000000"""PyPaperless generators.""" from .page import PageGenerator __all__ = ("PageGenerator",) paperless-api-4.1.1/pypaperless/models/generators/page.py000066400000000000000000000041001502576621300235550ustar00rootroot00000000000000"""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.py000066400000000000000000000062071502576621300216070ustar00rootroot00000000000000"""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/000077500000000000000000000000001502576621300214325ustar00rootroot00000000000000paperless-api-4.1.1/pypaperless/models/mixins/__init__.py000066400000000000000000000000451502576621300235420ustar00rootroot00000000000000"""Mixins for PyPaperless models.""" paperless-api-4.1.1/pypaperless/models/mixins/helpers/000077500000000000000000000000001502576621300230745ustar00rootroot00000000000000paperless-api-4.1.1/pypaperless/models/mixins/helpers/__init__.py000066400000000000000000000004401502576621300252030ustar00rootroot00000000000000"""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.py000066400000000000000000000017611502576621300252120ustar00rootroot00000000000000"""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.py000066400000000000000000000016241502576621300253750ustar00rootroot00000000000000"""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.py000066400000000000000000000073361502576621300252460ustar00rootroot00000000000000"""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.py000066400000000000000000000013751502576621300254210ustar00rootroot00000000000000"""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/000077500000000000000000000000001502576621300227155ustar00rootroot00000000000000paperless-api-4.1.1/pypaperless/models/mixins/models/__init__.py000066400000000000000000000006351502576621300250320ustar00rootroot00000000000000"""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.py000066400000000000000000000041751502576621300252200ustar00rootroot00000000000000"""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.py000066400000000000000000000005761502576621300255360ustar00rootroot00000000000000"""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.py000066400000000000000000000013631502576621300252130ustar00rootroot00000000000000"""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.py000066400000000000000000000013461502576621300252400ustar00rootroot00000000000000"""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.py000066400000000000000000000051211502576621300252270ustar00rootroot00000000000000"""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.py000066400000000000000000000051051502576621300215750ustar00rootroot00000000000000"""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.py000066400000000000000000000043001502576621300230450ustar00rootroot00000000000000"""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.py000066400000000000000000000016501502576621300235370ustar00rootroot00000000000000"""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.py000066400000000000000000000027371502576621300230250ustar00rootroot00000000000000"""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.py000066400000000000000000000034761502576621300230110ustar00rootroot00000000000000"""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.py000066400000000000000000000024641502576621300226750ustar00rootroot00000000000000"""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.py000066400000000000000000000034141502576621300220220ustar00rootroot00000000000000"""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.py000066400000000000000000000053141502576621300216250ustar00rootroot00000000000000"""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/000077500000000000000000000000001502576621300212635ustar00rootroot00000000000000paperless-api-4.1.1/pypaperless/models/utils/__init__.py000066400000000000000000000173631502576621300234060ustar00rootroot00000000000000"""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.py000066400000000000000000000131041502576621300225310ustar00rootroot00000000000000"""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.typed000066400000000000000000000000001502576621300203250ustar00rootroot00000000000000paperless-api-4.1.1/pyproject.toml000066400000000000000000000067201502576621300172120ustar00rootroot00000000000000[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/000077500000000000000000000000001502576621300155755ustar00rootroot00000000000000paperless-api-4.1.1/script/bootstrap000077500000000000000000000003261502576621300175410ustar00rootroot00000000000000#!/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/setup000077500000000000000000000012071502576621300166630ustar00rootroot00000000000000#!/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/000077500000000000000000000000001502576621300154335ustar00rootroot00000000000000paperless-api-4.1.1/tests/__init__.py000066400000000000000000000074421502576621300175530ustar00rootroot00000000000000"""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.py000066400000000000000000000077301502576621300176410ustar00rootroot00000000000000"""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.py000066400000000000000000000003761502576621300171410ustar00rootroot00000000000000"""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/000077500000000000000000000000001502576621300163445ustar00rootroot00000000000000paperless-api-4.1.1/tests/data/__init__.py000066400000000000000000000050241502576621300204560ustar00rootroot00000000000000"""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.json000066400000000000000000021276331502576621300222550ustar00rootroot00000000000000{ "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.py000066400000000000000000000746311502576621300177140ustar00rootroot00000000000000"""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.py000066400000000000000000000016031502576621300177720ustar00rootroot00000000000000"""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.py000066400000000000000000000042041502576621300177120ustar00rootroot00000000000000"""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.py000066400000000000000000000075011502576621300177060ustar00rootroot00000000000000"""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.py000066400000000000000000000011341502576621300177700ustar00rootroot00000000000000"""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.py000066400000000000000000000122061502576621300177070ustar00rootroot00000000000000"""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.py000066400000000000000000000020541502576621300177120ustar00rootroot00000000000000"""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.toml000066400000000000000000000006671502576621300173030ustar00rootroot00000000000000# 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.py000066400000000000000000000476361502576621300203540ustar00rootroot00000000000000"""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.py000066400000000000000000000356371502576621300217310ustar00rootroot00000000000000"""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.py000066400000000000000000000444651502576621300222110ustar00rootroot00000000000000"""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.lock000066400000000000000000003133721502576621300156060ustar00rootroot00000000000000version = 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" }, ]