diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 1f557cd4..f2b7301a 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -3,3 +3,6 @@ # Linting updates and fixes 292f58e2d60c1721349b1a0bb1bbbebf4809481e + +# Import reformatting +cff1e87a0d742be463d820382f467115fb18c8a2 diff --git a/.github/actionlint.yml b/.github/actionlint.yml new file mode 100644 index 00000000..23115024 --- /dev/null +++ b/.github/actionlint.yml @@ -0,0 +1,4 @@ +paths: + .github/workflows/check_migrations_sqlite.yml: + ignore: + - 'SC2086:info:10:54' diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 71847f7e..ace81138 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,13 +1,11 @@ # Keeps dependencies up to date - version: 2 updates: # Maintain dependencies for Python - package-ecosystem: "uv" directory: "/" schedule: - interval: "weekly" - day: "friday" + interval: "monthly" time: "00:00" cooldown: default-days: 7 @@ -15,8 +13,7 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" - day: "friday" + interval: "monthly" time: "00:00" groups: github: diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml index a52c3196..d9c55772 100644 --- a/.github/workflows/check-docs.yml +++ b/.github/workflows/check-docs.yml @@ -1,5 +1,11 @@ name: Docs + on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: pre_job: name: Path match check @@ -13,13 +19,14 @@ jobs: with: github_token: ${{ github.token }} paths: '["docs/**", "pyproject.toml", "uv.lock"]' + docs: name: Checking docs build needs: pre_job if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 with: fetch-depth: 0 - name: Install system dependencies @@ -27,12 +34,12 @@ jobs: sudo apt-get -y -qq update sudo apt-get install -y swig openssl libssl-dev - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.2.0 with: python-version: "3.10" activate-environment: "true" enable-cache: "true" - name: Install dependencies - run: uv sync --extra docs + run: uv sync --frozen --group docs - name: Check Docs build run: make docs diff --git a/.github/workflows/check_migrations_sqlite.yml b/.github/workflows/check_migrations_sqlite.yml index 91cbaf06..628aab94 100644 --- a/.github/workflows/check_migrations_sqlite.yml +++ b/.github/workflows/check_migrations_sqlite.yml @@ -1,5 +1,11 @@ name: Migrations for SQLite versions + on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: pre_job: name: Path match check @@ -13,33 +19,34 @@ jobs: with: github_token: ${{ github.token }} paths: '["morango/migrations/*.py", ".github/workflows/check_migrations_sqlite.yml", "pyproject.toml", "uv.lock"]' + build: name: Build wheel needs: pre_job + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 with: fetch-depth: 0 - name: Install uv - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.2.0 with: python-version: 3.9 enable-cache: "true" - name: Build wheel - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: uv build --wheel - name: Upload wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@v7.0.1 with: name: wheel path: dist/*.whl retention-days: 1 + migration_test: name: SQLite migration tests needs: [pre_job, build] + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest container: image: python:3.7-buster @@ -52,19 +59,16 @@ jobs: echo "Acquire::Check-Valid-Until \"false\";" > /etc/apt/apt.conf.d/99archive apt-get -y -qq update apt-get install -y build-essential tcl git-lfs - - uses: actions/checkout@v6 - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} + - uses: actions/checkout@v6.0.2 with: lfs: true fetch-depth: 0 - name: Download wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v8.0.1 with: name: wheel path: dist/ - name: Build SQLite 3.25.3 - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: | # Following the instructions from https://til.simonwillison.net/sqlite/ld-preload # to build SQLite from source, using version 3.25.3 @@ -76,16 +80,21 @@ jobs: 'import sqlite3; assert sqlite3.connect(":memory").execute("select sqlite_version()").fetchone()[0] == "3.25.3"' # Once we have confirmed that this works, set it for subsequent steps echo "LD_PRELOAD=$(realpath .libs/libsqlite3.so)" >> $GITHUB_ENV - - uses: actions/cache@v5 - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} + - uses: actions/cache@v5.0.5 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }} restore-keys: | ${{ runner.os }}-pip- + - name: Install uv + uses: astral-sh/setup-uv@v8.2.0 + with: + enable-cache: "true" + - name: Manually install test dependencies + run: | + uv pip install --system --group test - name: Install dependencies - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: pip install $(ls dist/*.whl | head -n 1)[test] + run: pip install "$(find dist -name '*.whl' | head -n 1)" - name: Run migrations if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: python tests/testapp/manage.py migrate diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..8162afe4 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,43 @@ +name: Linting + +on: + push: + branches: + - 'release-v**' + pull_request: + branches: + - 'release-v**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + pre_job: + name: Path match check + runs-on: ubuntu-latest + # Map a step output to a job output + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@master + with: + github_token: ${{ github.token }} + paths_ignore: '["**.po", "**.json"]' + + linting: + name: All file linting + needs: pre_job + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6.0.2 + - uses: astral-sh/setup-uv@v8.2.0 + with: + enable-cache: true + cache-python: true + - name: Install and verify lock + run: uv sync --group dev --locked + - name: Run prek hooks + run: uv run prek run --all-files --show-diff-on-failure diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index d986257c..2875d6cd 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,19 +1,18 @@ -# This workflow will upload a Python Package using uv when a release is created -# uv provides fast, modern Python package building and publishing - name: Upload Python Package + on: release: types: [published] + jobs: deploy: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 with: fetch-depth: 0 - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.2.0 with: python-version: 3.9 activate-environment: "true" diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 916207d9..f4163dae 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -1,5 +1,11 @@ name: Python tests + on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: pre_job: name: Path match check @@ -13,62 +19,61 @@ jobs: with: github_token: ${{ github.token }} paths: '["**.py", ".github/workflows/tox.yml", "tox.ini", "pyproject.toml", "uv.lock"]' + build: name: Build wheel needs: pre_job + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 with: fetch-depth: 0 - name: Install uv - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.2.0 with: python-version: 3.9 enable-cache: "true" - name: Build wheel - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: uv build --wheel - name: Upload wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@v7.0.1 with: name: wheel path: dist/*.whl retention-days: 1 + unit_test: name: Python unit tests needs: [pre_job, build] + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest strategy: max-parallel: 5 matrix: python-version: [3.9, '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Download wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v8.0.1 with: name: wheel path: dist/ - name: Install uv - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.2.0 with: python-version: "${{ matrix.python-version }}" activate-environment: "true" enable-cache: "true" - name: Install dependencies - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: uv sync --extra dev + run: uv sync --frozen --group dev - name: Test with tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: uv run tox --installpkg dist/*.whl -e py${{ matrix.python-version }} + run: uv run tox --installpkg "$(find dist/ -name '*.whl')" -e py${{ matrix.python-version }} + unit_test_eol_python: name: Python unit tests for EOL Python versions needs: [pre_job, build] + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest strategy: max-parallel: 5 @@ -77,30 +82,35 @@ jobs: container: image: python:${{ matrix.python-version }}-buster steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Download wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v8.0.1 with: name: wheel path: dist/ + - name: Install uv + uses: astral-sh/setup-uv@v8.2.0 + with: + enable-cache: "true" + - name: Manually install test dependencies + run: | + uv pip install --system --group test - name: Install tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: | python -m pip install --upgrade pip pip install tox - name: tox env cache - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/cache@v5 + uses: actions/cache@v5.0.5 with: path: ${{ github.workspace }}/.tox/py${{ matrix.python-version }} key: ${{ runner.os }}-tox-py${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }} - name: Test with tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: tox --installpkg dist/*.whl -e py${{ matrix.python-version }} + run: tox --installpkg "$(find dist/ -name '*.whl')" -e py${{ matrix.python-version }} --sitepackages + cryptography: name: Python unit tests + cryptography needs: [pre_job, build] + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest env: cryptography_version: '40.0.2' @@ -109,33 +119,30 @@ jobs: matrix: python-version: [3.9, '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Download wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v8.0.1 with: name: wheel path: dist/ - name: Install system dependencies - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: | sudo apt-get -y -qq update sudo apt-get install -y openssl libssl-dev - name: Install uv - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.2.0 with: python-version: "${{ matrix.python-version }}" enable-cache: "true" - name: Install dependencies - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: uv sync --extra dev + run: uv sync --frozen --group dev - name: Test with tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: uv run tox --installpkg dist/*.whl -e py${{ matrix.python-version }}-cryptography${{ env.cryptography_version }} + run: uv run tox --installpkg "$(find dist/ -name '*.whl')" -e py${{ matrix.python-version }}-cryptography${{ env.cryptography_version }} + cryptography_eol_python: name: Python unit tests + cryptography for EOL Python versions needs: [pre_job, build] + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest env: cryptography_version: '40.0.2' @@ -146,38 +153,42 @@ jobs: container: image: python:${{ matrix.python-version }}-buster steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Download wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v8.0.1 with: name: wheel path: dist/ - name: Install system dependencies - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: | echo "deb http://archive.debian.org/debian-archive/debian/ buster main" > /etc/apt/sources.list echo "deb http://archive.debian.org/debian-archive/debian-security/ buster/updates main" >> /etc/apt/sources.list echo "Acquire::Check-Valid-Until \"false\";" > /etc/apt/apt.conf.d/99archive apt-get -y -qq update apt-get install -y openssl libssl-dev + - name: Install uv + uses: astral-sh/setup-uv@v8.2.0 + with: + enable-cache: "true" + - name: Manually install test dependencies + run: | + uv pip install --system --group test - name: Install tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: | python -m pip install --upgrade pip pip install tox - name: tox env cache - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/cache@v5 + uses: actions/cache@v5.0.5 with: path: ${{ github.workspace }}/.tox/py${{ matrix.python-version }}-cryptography${{ env.cryptography_version }} key: ${{ runner.os }}-tox-py${{ matrix.python-version }}-crypto${{ env.cryptography_version }}-${{ hashFiles('pyproject.toml') }} - name: Test with tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: tox --installpkg dist/*.whl -e py${{ matrix.python-version }}-cryptography${{ env.cryptography_version }} + run: tox --installpkg "$(find dist/ -name '*.whl')" -e py${{ matrix.python-version }}-cryptography${{ env.cryptography_version }} --sitepackages + postgres: name: Python postgres unit tests needs: [pre_job, build] + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest services: # Label used to access the service container @@ -196,54 +207,76 @@ jobs: # Maps tcp port 5432 on service container to the host - 5432:5432 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Download wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v8.0.1 with: name: wheel path: dist/ - name: Install uv - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.2.0 with: python-version: "3.9" activate-environment: "true" enable-cache: "true" - name: Install dependencies - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: uv sync --extra dev + run: uv sync --frozen --group dev - name: Test with tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - run: uv run tox --installpkg dist/*.whl --discover $(uv python find 3.9) -e postgres + run: uv run tox --installpkg "$(find dist/ -name '*.whl')" --discover "$(uv python find 3.9)" -e postgres + windows: name: Python unit tests on Windows Server needs: [pre_job, build] + if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: windows-latest strategy: max-parallel: 5 matrix: python-version: [3.8] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Download wheel artifact - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v8.0.1 with: name: wheel path: dist/ - name: Set up Python ${{ matrix.python-version }} - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} - uses: actions/setup-python@v6 + uses: actions/setup-python@v6.2.0 with: python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v8.2.0 + with: + enable-cache: "true" + - name: Manually install test dependencies + run: | + uv pip install --system --group test - name: Install tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: | python -m pip install --upgrade pip pip install tox - name: Test with tox - if: ${{ needs.pre_job.outputs.should_skip != 'true' }} run: | $wheel = Get-ChildItem dist\*.whl | Select-Object -ExpandProperty FullName -First 1 - tox --installpkg $wheel -e windows + tox --installpkg $wheel -e windows --sitepackages + + # Single stable check for branch protection. Skipped matrix jobs don't + # produce per-version check runs, so matrix-suffixed required checks hang + # as "Expected" on PRs that skip the tests; require this job instead. + required_checks: + name: Python tests + needs: + - pre_job + - build + - unit_test + - unit_test_eol_python + - cryptography + - cryptography_eol_python + - postgres + - windows + if: always() + runs-on: ubuntu-latest + steps: + - name: Fail if any needed job failed or was cancelled + if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: exit 1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a18c0a3..542d4c49 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.2.3 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: check-yaml @@ -9,20 +9,20 @@ repos: - id: end-of-file-fixer exclude: '^.+?\.json$' - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.8 + rev: v0.15.16 hooks: - id: ruff args: [--fix] - id: ruff-format - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.11.3 + rev: 0.11.6 hooks: - id: uv-lock - repo: https://github.com/google/yamlfmt - rev: v0.14.0 + rev: v0.21.0 hooks: - id: yamlfmt - repo: https://github.com/rhysd/actionlint - rev: v1.7.7 + rev: v1.7.11 hooks: - id: actionlint diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7bfba4af..e10f9188 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -12,6 +12,6 @@ build: create_environment: - uv venv "${READTHEDOCS_VIRTUALENV_PATH}" install: - - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --extra docs + - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --group docs sphinx: configuration: docs/conf.py diff --git a/.yamlfmt b/.yamlfmt new file mode 100644 index 00000000..74e684b1 --- /dev/null +++ b/.yamlfmt @@ -0,0 +1,3 @@ +formatter: + retain_line_breaks: true + eof_newline: true diff --git a/README.md b/README.md index 4bd0e340..34cb741c 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,9 @@ See [morango.readthedocs.io](https://morango.readthedocs.io) for documentation o To start contributing to Morango, first make sure you [have `uv` installed](https://docs.astral.sh/uv/getting-started/installation/). -Create a virtual environment, which will create it in the `.venv/` directory, with the python version defined in `.python-version`: +The following command will create a virtual environment in `.venv/`, with the python version defined in `.python-version`, and install development dependencies: ```bash -uv venv -``` - -Then install dependencies: -```bash -uv sync --all-extras +uv sync --group dev ``` If you get errors during installation, you may need to install system packages such as `openssl` and `libssl-dev`. @@ -51,7 +46,7 @@ To build and edit the docs, run: ```bash # install requirements (if necessary) -uv sync --extra docs +uv sync --group docs # build docs make docs diff --git a/morango/api/permissions.py b/morango/api/permissions.py index ecc7bc25..416cd4f2 100644 --- a/morango/api/permissions.py +++ b/morango/api/permissions.py @@ -1,7 +1,10 @@ import json -from django.contrib.auth import authenticate, get_user_model -from rest_framework import authentication, exceptions, permissions +from django.contrib.auth import authenticate +from django.contrib.auth import get_user_model +from rest_framework import authentication +from rest_framework import exceptions +from rest_framework import permissions from morango.models.core import TransferSession from morango.utils import SETTINGS diff --git a/morango/api/serializers.py b/morango/api/serializers.py index 8b9a8dc9..150959fc 100644 --- a/morango/api/serializers.py +++ b/morango/api/serializers.py @@ -1,15 +1,14 @@ -from rest_framework import exceptions, serializers +from rest_framework import exceptions +from rest_framework import serializers from rest_framework.fields import ReadOnlyField from ..models.certificates import Nonce -from ..models.core import ( - Buffer, - Certificate, - InstanceIDModel, - RecordMaxCounterBuffer, - SyncSession, - TransferSession, -) +from ..models.core import Buffer +from ..models.core import Certificate +from ..models.core import InstanceIDModel +from ..models.core import RecordMaxCounterBuffer +from ..models.core import SyncSession +from ..models.core import TransferSession from ..models.fields.crypto import SharedKey from ..utils import SETTINGS from .fields import PublicKeyField diff --git a/morango/api/urls.py b/morango/api/urls.py index 9d391960..6c77d64f 100644 --- a/morango/api/urls.py +++ b/morango/api/urls.py @@ -1,15 +1,13 @@ from rest_framework import routers -from .viewsets import ( - BufferViewSet, - CertificateChainViewSet, - CertificateViewSet, - MorangoInfoViewSet, - NonceViewSet, - PublicKeyViewSet, - SyncSessionViewSet, - TransferSessionViewSet, -) +from .viewsets import BufferViewSet +from .viewsets import CertificateChainViewSet +from .viewsets import CertificateViewSet +from .viewsets import MorangoInfoViewSet +from .viewsets import NonceViewSet +from .viewsets import PublicKeyViewSet +from .viewsets import SyncSessionViewSet +from .viewsets import TransferSessionViewSet router = routers.SimpleRouter() router.register(r"certificates", CertificateViewSet, basename="certificates") diff --git a/morango/api/viewsets.py b/morango/api/viewsets.py index fa934f0e..70990944 100644 --- a/morango/api/viewsets.py +++ b/morango/api/viewsets.py @@ -6,20 +6,33 @@ from django.core.exceptions import ValidationError from django.utils import timezone from ipware import get_client_ip -from rest_framework import mixins, pagination, response, status, viewsets +from rest_framework import mixins +from rest_framework import pagination +from rest_framework import response +from rest_framework import status +from rest_framework import viewsets from rest_framework.parsers import JSONParser import morango from morango import errors -from morango.api import permissions, serializers -from morango.constants import transfer_stages, transfer_statuses -from morango.constants.capabilities import ASYNC_OPERATIONS, GZIP_BUFFER_POST +from morango.api import permissions +from morango.api import serializers +from morango.constants import transfer_stages +from morango.constants import transfer_statuses +from morango.constants.capabilities import ASYNC_OPERATIONS +from morango.constants.capabilities import GZIP_BUFFER_POST from morango.models import certificates -from morango.models.core import Buffer, Certificate, InstanceIDModel, SyncSession, TransferSession +from morango.models.core import Buffer +from morango.models.core import Certificate +from morango.models.core import InstanceIDModel +from morango.models.core import SyncSession +from morango.models.core import TransferSession from morango.models.fields.crypto import SharedKey from morango.sync.context import LocalSessionContext from morango.sync.controller import SessionController -from morango.utils import CAPABILITIES, _assert, parse_capabilities_from_server_request +from morango.utils import _assert +from morango.utils import CAPABILITIES +from morango.utils import parse_capabilities_from_server_request if GZIP_BUFFER_POST in CAPABILITIES: from .parsers import GzipParser diff --git a/morango/apps.py b/morango/apps.py index 118ff964..d3f73fb2 100644 --- a/morango/apps.py +++ b/morango/apps.py @@ -1,6 +1,7 @@ from django.apps import AppConfig -from morango.registry import session_middleware, syncable_models +from morango.registry import session_middleware +from morango.registry import syncable_models class MorangoConfig(AppConfig): diff --git a/morango/management/commands/cleanupsyncs.py b/morango/management/commands/cleanupsyncs.py index fb31a107..326edfa8 100644 --- a/morango/management/commands/cleanupsyncs.py +++ b/morango/management/commands/cleanupsyncs.py @@ -6,7 +6,8 @@ from django.db import transaction from django.utils import timezone -from morango.models import SyncSession, TransferSession +from morango.models import SyncSession +from morango.models import TransferSession logger = logging.getLogger(__name__) diff --git a/morango/migrations/0001_initial.py b/morango/migrations/0001_initial.py index 5818b01d..cde01605 100644 --- a/morango/migrations/0001_initial.py +++ b/morango/migrations/0001_initial.py @@ -2,7 +2,8 @@ # Generated by Django 1.9 on 2017-05-08 23:42 import django.db.models.deletion import django.utils.timezone -from django.db import migrations, models +from django.db import migrations +from django.db import models import morango.models.fields.crypto import morango.models.fields.uuids diff --git a/morango/migrations/0001_squashed_0024_auto_20240129_1757.py b/morango/migrations/0001_squashed_0024_auto_20240129_1757.py index ef74ef89..29ca5478 100644 --- a/morango/migrations/0001_squashed_0024_auto_20240129_1757.py +++ b/morango/migrations/0001_squashed_0024_auto_20240129_1757.py @@ -2,7 +2,8 @@ import django.db.models.deletion import django.db.models.manager import django.utils.timezone -from django.db import migrations, models +from django.db import migrations +from django.db import models import morango.models.fields.crypto import morango.models.fields.uuids diff --git a/morango/migrations/0002_auto_20170511_0400.py b/morango/migrations/0002_auto_20170511_0400.py index b6e20d50..ccd39321 100644 --- a/morango/migrations/0002_auto_20170511_0400.py +++ b/morango/migrations/0002_auto_20170511_0400.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2017-05-11 04:00 import django.db.models.manager -from django.db import migrations, models +from django.db import migrations +from django.db import models import morango.models.fields.uuids diff --git a/morango/migrations/0002_store_idx_morango_deserialize.py b/morango/migrations/0002_store_idx_morango_deserialize.py index f86568c8..fcacfc2c 100644 --- a/morango/migrations/0002_store_idx_morango_deserialize.py +++ b/morango/migrations/0002_store_idx_morango_deserialize.py @@ -1,5 +1,6 @@ # Generated by Django 3.2.24 on 2024-10-18 23:18 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0003_auto_20170519_0543.py b/morango/migrations/0003_auto_20170519_0543.py index 1e658101..2379c8a2 100644 --- a/morango/migrations/0003_auto_20170519_0543.py +++ b/morango/migrations/0003_auto_20170519_0543.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9 on 2017-05-19 05:43 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0003_store_deserialization_errors.py b/morango/migrations/0003_store_deserialization_errors.py index baf09ab3..244f1cd0 100644 --- a/morango/migrations/0003_store_deserialization_errors.py +++ b/morango/migrations/0003_store_deserialization_errors.py @@ -1,5 +1,6 @@ # Generated by Django 3.2.25 on 2026-04-14 15:54 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0004_self_ref_order.py b/morango/migrations/0004_self_ref_order.py index d28d17d8..960f000a 100644 --- a/morango/migrations/0004_self_ref_order.py +++ b/morango/migrations/0004_self_ref_order.py @@ -1,24 +1,28 @@ # Generated by Django 3.2.25 on 2026-04-22 10:53 import django.core.validators -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): - dependencies = [ - ('morango', '0003_store_deserialization_errors'), + ("morango", "0003_store_deserialization_errors"), ] operations = [ migrations.AddField( - model_name='buffer', - name='_self_ref_order', - field=models.IntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)]), + model_name="buffer", + name="_self_ref_order", + field=models.IntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)] + ), ), migrations.AddField( - model_name='store', - name='_self_ref_order', - field=models.IntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)]), + model_name="store", + name="_self_ref_order", + field=models.IntegerField( + blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)] + ), ), ] diff --git a/morango/migrations/0006_instanceidmodel_system_id.py b/morango/migrations/0006_instanceidmodel_system_id.py index 82ed6268..cefc008f 100644 --- a/morango/migrations/0006_instanceidmodel_system_id.py +++ b/morango/migrations/0006_instanceidmodel_system_id.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9 on 2017-06-30 00:15 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0007_auto_20171018_1615.py b/morango/migrations/0007_auto_20171018_1615.py index 635f57fb..7aad6375 100644 --- a/morango/migrations/0007_auto_20171018_1615.py +++ b/morango/migrations/0007_auto_20171018_1615.py @@ -4,7 +4,8 @@ import django.db.models.deletion import django.utils.timezone -from django.db import migrations, models +from django.db import migrations +from django.db import models from django.utils.timezone import utc import morango.models.fields.uuids diff --git a/morango/migrations/0008_auto_20171114_2217.py b/morango/migrations/0008_auto_20171114_2217.py index 0826238f..f83e951a 100644 --- a/morango/migrations/0008_auto_20171114_2217.py +++ b/morango/migrations/0008_auto_20171114_2217.py @@ -2,7 +2,8 @@ # Generated by Django 1.9.7 on 2017-11-14 22:17 import django.db.models.deletion import django.db.models.manager -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0010_auto_20171206_1615.py b/morango/migrations/0010_auto_20171206_1615.py index d61dff7b..6f5b4983 100644 --- a/morango/migrations/0010_auto_20171206_1615.py +++ b/morango/migrations/0010_auto_20171206_1615.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.13 on 2017-12-06 22:15 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0011_sharedkey.py b/morango/migrations/0011_sharedkey.py index 7daeb18e..eba0cf0d 100644 --- a/morango/migrations/0011_sharedkey.py +++ b/morango/migrations/0011_sharedkey.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.13 on 2018-06-12 18:38 -from django.db import migrations, models +from django.db import migrations +from django.db import models import morango.models.fields.crypto diff --git a/morango/migrations/0012_auto_20180927_1658.py b/morango/migrations/0012_auto_20180927_1658.py index 26b8c34f..a72e10f1 100644 --- a/morango/migrations/0012_auto_20180927_1658.py +++ b/morango/migrations/0012_auto_20180927_1658.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.15 on 2018-09-27 16:58 -from django.db import migrations, models +from django.db import migrations +from django.db import models import morango.models.fields.uuids diff --git a/morango/migrations/0014_syncsession_extra_fields.py b/morango/migrations/0014_syncsession_extra_fields.py index ab4b1874..fc31913c 100644 --- a/morango/migrations/0014_syncsession_extra_fields.py +++ b/morango/migrations/0014_syncsession_extra_fields.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.27 on 2019-12-30 18:28 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0015_auto_20200508_2104.py b/morango/migrations/0015_auto_20200508_2104.py index 383a12e9..f1e40acf 100644 --- a/morango/migrations/0015_auto_20200508_2104.py +++ b/morango/migrations/0015_auto_20200508_2104.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2020-05-08 21:04 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0016_store_deserialization_error.py b/morango/migrations/0016_store_deserialization_error.py index bc5a9934..796c84c6 100644 --- a/morango/migrations/0016_store_deserialization_error.py +++ b/morango/migrations/0016_store_deserialization_error.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.28 on 2020-06-10 23:48 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0018_auto_20210714_2216.py b/morango/migrations/0018_auto_20210714_2216.py index b3c3d191..24bb4460 100644 --- a/morango/migrations/0018_auto_20210714_2216.py +++ b/morango/migrations/0018_auto_20210714_2216.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2021-07-14 22:16 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0019_auto_20220113_1807.py b/morango/migrations/0019_auto_20220113_1807.py index 2ed80e3b..f187461a 100644 --- a/morango/migrations/0019_auto_20220113_1807.py +++ b/morango/migrations/0019_auto_20220113_1807.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2022-01-13 18:07 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0021_store_partition_index_create.py b/morango/migrations/0021_store_partition_index_create.py index a4030b38..603cbb27 100644 --- a/morango/migrations/0021_store_partition_index_create.py +++ b/morango/migrations/0021_store_partition_index_create.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2022-04-27 16:59 -from django.db import migrations, models +from django.db import migrations +from django.db import models class ConditionalConcurrentTextPatternIndex(migrations.AddIndex): diff --git a/morango/migrations/0023_add_instance_id_fields.py b/morango/migrations/0023_add_instance_id_fields.py index fb6c707c..0550348e 100644 --- a/morango/migrations/0023_add_instance_id_fields.py +++ b/morango/migrations/0023_add_instance_id_fields.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.29 on 2023-01-31 19:03 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/migrations/0024_auto_20240129_1757.py b/morango/migrations/0024_auto_20240129_1757.py index e3c66308..4ec6abc8 100644 --- a/morango/migrations/0024_auto_20240129_1757.py +++ b/morango/migrations/0024_auto_20240129_1757.py @@ -1,5 +1,6 @@ # Generated by Django 3.2.23 on 2024-01-29 17:57 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/morango/models/__init__.py b/morango/models/__init__.py index 2e48ad0e..2a336666 100644 --- a/morango/models/__init__.py +++ b/morango/models/__init__.py @@ -1,19 +1,21 @@ from morango.models import signals -from morango.models.certificates import Certificate, Filter, Nonce, Scope, ScopeDefinition -from morango.models.core import ( - Buffer, - DatabaseIDModel, - DatabaseMaxCounter, - DeletedModels, - HardDeletedModels, - InstanceIDModel, - RecordMaxCounter, - RecordMaxCounterBuffer, - Store, - SyncableModel, - SyncSession, - TransferSession, -) +from morango.models.certificates import Certificate +from morango.models.certificates import Filter +from morango.models.certificates import Nonce +from morango.models.certificates import Scope +from morango.models.certificates import ScopeDefinition +from morango.models.core import Buffer +from morango.models.core import DatabaseIDModel +from morango.models.core import DatabaseMaxCounter +from morango.models.core import DeletedModels +from morango.models.core import HardDeletedModels +from morango.models.core import InstanceIDModel +from morango.models.core import RecordMaxCounter +from morango.models.core import RecordMaxCounterBuffer +from morango.models.core import Store +from morango.models.core import SyncableModel +from morango.models.core import SyncSession +from morango.models.core import TransferSession from morango.models.fields import * # noqa from morango.models.fields import __all__ as fields_all from morango.models.fields.crypto import SharedKey diff --git a/morango/models/certificates.py b/morango/models/certificates.py index 36159d31..341af0bd 100644 --- a/morango/models/certificates.py +++ b/morango/models/certificates.py @@ -11,23 +11,25 @@ import mptt.models from django.core.management import call_command -from django.db import connection, models, transaction +from django.db import connection +from django.db import models +from django.db import transaction from django.db.utils import OperationalError from django.utils import timezone -from morango.errors import ( - CertificateIDInvalid, - CertificateProfileInvalid, - CertificateRootScopeInvalid, - CertificateScopeNotSubset, - CertificateSignatureInvalid, - NonceDoesNotExist, - NonceExpired, -) +from morango.errors import CertificateIDInvalid +from morango.errors import CertificateProfileInvalid +from morango.errors import CertificateRootScopeInvalid +from morango.errors import CertificateScopeNotSubset +from morango.errors import CertificateSignatureInvalid +from morango.errors import NonceDoesNotExist +from morango.errors import NonceExpired from morango.sync.backends.utils import load_backend from morango.utils import _assert -from .fields.crypto import Key, PrivateKeyField, PublicKeyField +from .fields.crypto import Key +from .fields.crypto import PrivateKeyField +from .fields.crypto import PublicKeyField from .fields.uuids import UUIDModelMixin diff --git a/morango/models/core.py b/morango/models/core.py index 343d77c0..bb27bd46 100644 --- a/morango/models/core.py +++ b/morango/models/core.py @@ -2,13 +2,23 @@ import json import logging import uuid -from collections import defaultdict, namedtuple +from collections import defaultdict +from collections import namedtuple from functools import reduce from django.core import exceptions from django.core.validators import MinValueValidator -from django.db import connection, models, router, transaction -from django.db.models import F, Func, Max, Q, TextField, Value, signals +from django.db import connection +from django.db import models +from django.db import router +from django.db import transaction +from django.db.models import F +from django.db.models import Func +from django.db.models import Max +from django.db.models import Q +from django.db.models import signals +from django.db.models import TextField +from django.db.models import Value from django.db.models.deletion import Collector from django.db.models.expressions import CombinedExpression from django.db.models.fields.related import ForeignKey @@ -17,15 +27,23 @@ from django.utils.functional import cached_property from morango import proquint -from morango.constants import transfer_stages, transfer_statuses +from morango.constants import transfer_stages +from morango.constants import transfer_statuses from morango.errors import InvalidMorangoSourceId -from morango.models.certificates import Certificate, Filter -from morango.models.fields.uuids import UUIDField, UUIDModelMixin, sha2_uuid +from morango.models.certificates import Certificate +from morango.models.certificates import Filter +from morango.models.fields.uuids import sha2_uuid +from morango.models.fields.uuids import UUIDField +from morango.models.fields.uuids import UUIDModelMixin from morango.models.fsic_utils import remove_redundant_instance_counters from morango.models.manager import SyncableModelManager -from morango.models.utils import get_0_4_system_parameters, get_0_5_mac_address, get_0_5_system_id +from morango.models.utils import get_0_4_system_parameters +from morango.models.utils import get_0_5_mac_address +from morango.models.utils import get_0_5_system_id from morango.registry import syncable_models -from morango.utils import SETTINGS, _assert, exception_path +from morango.utils import _assert +from morango.utils import exception_path +from morango.utils import SETTINGS logger = logging.getLogger(__name__) @@ -392,9 +410,7 @@ class AbstractStore(models.Model): conflicting_serialized_data = models.TextField(blank=True) _self_ref_fk = models.CharField(max_length=32, blank=True) - _self_ref_order = models.IntegerField( - blank=True, null=True, validators=[MinValueValidator(0)] - ) + _self_ref_order = models.IntegerField(blank=True, null=True, validators=[MinValueValidator(0)]) class Meta: abstract = True diff --git a/morango/models/fields/__init__.py b/morango/models/fields/__init__.py index ad6c8fae..3a312941 100644 --- a/morango/models/fields/__init__.py +++ b/morango/models/fields/__init__.py @@ -1,4 +1,5 @@ -from morango.models.fields.crypto import PrivateKeyField, PublicKeyField +from morango.models.fields.crypto import PrivateKeyField +from morango.models.fields.crypto import PublicKeyField from morango.models.fields.uuids import UUIDField __all__ = ["UUIDField", "PublicKeyField", "PrivateKeyField"] diff --git a/morango/models/fields/crypto.py b/morango/models/fields/crypto.py index 434e32a1..4db78843 100644 --- a/morango/models/fields/crypto.py +++ b/morango/models/fields/crypto.py @@ -10,10 +10,12 @@ import sys import rsa as PYRSA -from django.db import models, transaction +from django.db import models +from django.db import transaction try: - from M2Crypto import BIO as M2BIO, RSA as M2RSA + from M2Crypto import BIO as M2BIO + from M2Crypto import RSA as M2RSA M2CRYPTO_EXISTS = True except ImportError: @@ -34,14 +36,10 @@ from cryptography.hazmat.backends import default_backend crypto_backend = default_backend() - from cryptography.hazmat.primitives import ( - hashes as crypto_hashes, - serialization as crypto_serialization, - ) - from cryptography.hazmat.primitives.asymmetric import ( - padding as crypto_padding, - rsa as crypto_rsa, - ) + from cryptography.hazmat.primitives import hashes as crypto_hashes + from cryptography.hazmat.primitives import serialization as crypto_serialization + from cryptography.hazmat.primitives.asymmetric import padding as crypto_padding + from cryptography.hazmat.primitives.asymmetric import rsa as crypto_rsa # Ignore cryptography versions that do not support the 'sign' method if not hasattr(crypto_rsa.RSAPrivateKey, "sign"): @@ -57,7 +55,8 @@ # Otherwise raise the error again to avoid silently catching other errors raise -from base64 import decodebytes as b64decode, encodebytes as b64encode +from base64 import decodebytes as b64decode +from base64 import encodebytes as b64encode PKCS8_HEADER = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A" diff --git a/morango/registry.py b/morango/registry.py index 53569564..745b1f4c 100644 --- a/morango/registry.py +++ b/morango/registry.py @@ -5,19 +5,22 @@ import inspect import sys -from collections import OrderedDict, defaultdict -from typing import Generator, Optional +from collections import defaultdict +from collections import OrderedDict +from typing import Generator +from typing import Optional -from django.db.models import F, QuerySet +from django.db.models import F +from django.db.models import QuerySet from django.db.models.fields.related import ForeignKey from morango.constants import transfer_stages -from morango.errors import ( - InvalidMorangoModelConfiguration, - ModelRegistryNotReady, - UnsupportedFieldType, -) -from morango.utils import SETTINGS, do_import, self_referential_fk +from morango.errors import InvalidMorangoModelConfiguration +from morango.errors import ModelRegistryNotReady +from morango.errors import UnsupportedFieldType +from morango.utils import do_import +from morango.utils import self_referential_fk +from morango.utils import SETTINGS _UNSET = object() diff --git a/morango/sync/backends/base.py b/morango/sync/backends/base.py index 8c37db0b..c7ebda02 100644 --- a/morango/sync/backends/base.py +++ b/morango/sync/backends/base.py @@ -1,6 +1,9 @@ from contextlib import contextmanager -from morango.models.core import Buffer, RecordMaxCounter, RecordMaxCounterBuffer, Store +from morango.models.core import Buffer +from morango.models.core import RecordMaxCounter +from morango.models.core import RecordMaxCounterBuffer +from morango.models.core import Store class BaseSQLWrapper(object): diff --git a/morango/sync/context.py b/morango/sync/context.py index 87a3a410..1c040966 100644 --- a/morango/sync/context.py +++ b/morango/sync/context.py @@ -1,8 +1,11 @@ -from morango.constants import transfer_stages, transfer_statuses +from morango.constants import transfer_stages +from morango.constants import transfer_statuses from morango.errors import MorangoContextUpdateError from morango.models.certificates import Filter -from morango.models.core import SyncSession, TransferSession -from morango.utils import CAPABILITIES, parse_capabilities_from_server_request +from morango.models.core import SyncSession +from morango.models.core import TransferSession +from morango.utils import CAPABILITIES +from morango.utils import parse_capabilities_from_server_request class SessionContext(object): diff --git a/morango/sync/controller.py b/morango/sync/controller.py index c076b284..e29d944c 100644 --- a/morango/sync/controller.py +++ b/morango/sync/controller.py @@ -2,9 +2,11 @@ import math from time import sleep -from morango.constants import transfer_stages, transfer_statuses +from morango.constants import transfer_stages +from morango.constants import transfer_statuses from morango.registry import session_middleware -from morango.sync.operations import OperationLogger, _deserialize_from_store +from morango.sync.operations import _deserialize_from_store +from morango.sync.operations import OperationLogger from morango.sync.stream.serialize import serialize_into_store from morango.sync.utils import SyncSignalGroup from morango.utils import _assert diff --git a/morango/sync/db.py b/morango/sync/db.py index 6ee04674..aa4f4c96 100644 --- a/morango/sync/db.py +++ b/morango/sync/db.py @@ -1,7 +1,8 @@ import logging from contextlib import contextmanager -from django.db import connection, transaction +from django.db import connection +from django.db import transaction from morango.sync.backends.utils import load_backend from morango.sync.utils import lock_partitions diff --git a/morango/sync/session.py b/morango/sync/session.py index c8c748a1..c8ee2b18 100644 --- a/morango/sync/session.py +++ b/morango/sync/session.py @@ -6,7 +6,8 @@ from requests.utils import super_len from morango import __version__ -from morango.utils import SETTINGS, serialize_capabilities_to_client_request +from morango.utils import serialize_capabilities_to_client_request +from morango.utils import SETTINGS logger = logging.getLogger(__name__) diff --git a/morango/sync/stream/core.py b/morango/sync/stream/core.py index 76a8584e..03b802a9 100644 --- a/morango/sync/stream/core.py +++ b/morango/sync/stream/core.py @@ -6,7 +6,14 @@ """ import abc -from typing import Any, Callable, Generic, Iterable, Iterator, List, Optional, TypeVar +from typing import Any +from typing import Callable +from typing import Generic +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import TypeVar T = TypeVar("T") diff --git a/morango/sync/stream/serialize.py b/morango/sync/stream/serialize.py index 172768f1..65b8ebd2 100644 --- a/morango/sync/stream/serialize.py +++ b/morango/sync/stream/serialize.py @@ -1,22 +1,27 @@ import json import logging -from typing import Generator, List, Optional, Type +from typing import Generator +from typing import List +from typing import Optional +from typing import Type from django.core.serializers.json import DjangoJSONEncoder from django.db.models import Q from morango.models.certificates import Filter -from morango.models.core import ( - DatabaseMaxCounter, - DeletedModels, - HardDeletedModels, - InstanceIDModel, - RecordMaxCounter, - Store, - SyncableModel, -) +from morango.models.core import DatabaseMaxCounter +from morango.models.core import DeletedModels +from morango.models.core import HardDeletedModels +from morango.models.core import InstanceIDModel +from morango.models.core import RecordMaxCounter +from morango.models.core import Store +from morango.models.core import SyncableModel from morango.registry import syncable_models -from morango.sync.stream.core import Buffer, Sink, Source, Transform, Unbuffer +from morango.sync.stream.core import Buffer +from morango.sync.stream.core import Sink +from morango.sync.stream.core import Source +from morango.sync.stream.core import Transform +from morango.sync.stream.core import Unbuffer logger = logging.getLogger(__name__) diff --git a/morango/sync/syncsession.py b/morango/sync/syncsession.py index c74d73d0..9c387e98 100644 --- a/morango/sync/syncsession.py +++ b/morango/sync/syncsession.py @@ -8,30 +8,42 @@ import socket import uuid from io import BytesIO -from urllib.parse import urljoin, urlparse +from urllib.parse import urljoin +from urllib.parse import urlparse -from django.db import connection, transaction +from django.db import connection +from django.db import transaction from django.utils import timezone from requests.adapters import HTTPAdapter from requests.exceptions import HTTPError from requests.packages.urllib3.util.retry import Retry -from morango.api.serializers import CertificateSerializer, InstanceIDSerializer -from morango.constants import api_urls, transfer_stages, transfer_statuses -from morango.constants.capabilities import ALLOW_CERTIFICATE_PUSHING, GZIP_BUFFER_POST -from morango.errors import ( - CertificateSignatureInvalid, - MorangoError, - MorangoResumeSyncError, - MorangoServerDoesNotAllowNewCertPush, -) -from morango.models.certificates import Certificate, Filter, Key -from morango.models.core import InstanceIDModel, SyncSession +from morango.api.serializers import CertificateSerializer +from morango.api.serializers import InstanceIDSerializer +from morango.constants import api_urls +from morango.constants import transfer_stages +from morango.constants import transfer_statuses +from morango.constants.capabilities import ALLOW_CERTIFICATE_PUSHING +from morango.constants.capabilities import GZIP_BUFFER_POST +from morango.errors import CertificateSignatureInvalid +from morango.errors import MorangoError +from morango.errors import MorangoResumeSyncError +from morango.errors import MorangoServerDoesNotAllowNewCertPush +from morango.models.certificates import Certificate +from morango.models.certificates import Filter +from morango.models.certificates import Key +from morango.models.core import InstanceIDModel +from morango.models.core import SyncSession from morango.sync.backends.utils import load_backend -from morango.sync.context import CompositeSessionContext, LocalSessionContext, NetworkSessionContext +from morango.sync.context import CompositeSessionContext +from morango.sync.context import LocalSessionContext +from morango.sync.context import NetworkSessionContext from morango.sync.controller import SessionController -from morango.sync.utils import SyncSignal, SyncSignalGroup, lock_partitions -from morango.utils import CAPABILITIES, pid_exists +from morango.sync.utils import lock_partitions +from morango.sync.utils import SyncSignal +from morango.sync.utils import SyncSignalGroup +from morango.utils import CAPABILITIES +from morango.utils import pid_exists from .session import SessionWrapper diff --git a/morango/sync/utils.py b/morango/sync/utils.py index 05aa1232..fa4f6919 100644 --- a/morango/sync/utils.py +++ b/morango/sync/utils.py @@ -5,7 +5,9 @@ from django.db import transaction from rest_framework.exceptions import ValidationError -from morango.models.core import Buffer, RecordMaxCounterBuffer, SyncableModel +from morango.models.core import Buffer +from morango.models.core import RecordMaxCounterBuffer +from morango.models.core import SyncableModel from morango.registry import syncable_models logger = logging.getLogger(__name__) diff --git a/morango/urls.py b/morango/urls.py index 497befeb..01799d66 100644 --- a/morango/urls.py +++ b/morango/urls.py @@ -1,3 +1,4 @@ -from django.urls import include, path +from django.urls import include +from django.urls import path urlpatterns = [path("api/morango/v1/", include("morango.api.urls"))] diff --git a/morango/utils.py b/morango/utils.py index 09af41dc..f47205a7 100644 --- a/morango/utils.py +++ b/morango/utils.py @@ -5,13 +5,11 @@ from django.conf import settings from morango.constants import settings as default_settings -from morango.constants.capabilities import ( - ALLOW_CERTIFICATE_PUSHING, - ASYNC_OPERATIONS, - FSIC_V2_FORMAT, - GZIP_BUFFER_POST, - SELF_REF_ORDER, -) +from morango.constants.capabilities import ALLOW_CERTIFICATE_PUSHING +from morango.constants.capabilities import ASYNC_OPERATIONS +from morango.constants.capabilities import FSIC_V2_FORMAT +from morango.constants.capabilities import GZIP_BUFFER_POST +from morango.constants.capabilities import SELF_REF_ORDER def do_import(import_string): diff --git a/pyproject.toml b/pyproject.toml index beb3b70f..ee9f6d18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ dependencies = [ "ifcfg", ] -[project.optional-dependencies] +[dependency-groups] test = [ "factory-boy>=3.0,<4", "mock>=4.0,<6", @@ -48,6 +48,7 @@ test = [ ] dev = [ + {include-group = "test"}, "prek>=0.3.6; python_version>='3.8'", "tox>=4; python_version>='3.9'", "tox<4; python_version<'3.9'", @@ -68,6 +69,7 @@ docs = [ "ifcfg==0.24", ] +[project.optional-dependencies] postgres = [ "M2Crypto==0.41.0", "cryptography==40.0.2", @@ -124,6 +126,8 @@ ignore = [ [tool.ruff.lint.isort] combine-as-imports = true +force-single-line = true +order-by-type = false [tool.ruff.lint.mccabe] max-complexity = 10 diff --git a/tests/testapp/facility_profile/migrations/0001_initial.py b/tests/testapp/facility_profile/migrations/0001_initial.py index 642b228a..6e3b48ae 100644 --- a/tests/testapp/facility_profile/migrations/0001_initial.py +++ b/tests/testapp/facility_profile/migrations/0001_initial.py @@ -6,7 +6,8 @@ import django.utils.timezone import mptt.fields from django.conf import settings -from django.db import migrations, models +from django.db import migrations +from django.db import models import facility_profile.models import morango.models.fields.uuids diff --git a/tests/testapp/facility_profile/migrations/0002_auto_20220427_0449.py b/tests/testapp/facility_profile/migrations/0002_auto_20220427_0449.py index 4d29f113..b6d27e9f 100644 --- a/tests/testapp/facility_profile/migrations/0002_auto_20220427_0449.py +++ b/tests/testapp/facility_profile/migrations/0002_auto_20220427_0449.py @@ -2,7 +2,8 @@ # Generated by Django 1.11.29 on 2022-04-27 04:49 import django.db.models.deletion from django.conf import settings -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/tests/testapp/facility_profile/migrations/0003_auto_20240129_2025.py b/tests/testapp/facility_profile/migrations/0003_auto_20240129_2025.py index 24b0c268..e55c185c 100644 --- a/tests/testapp/facility_profile/migrations/0003_auto_20240129_2025.py +++ b/tests/testapp/facility_profile/migrations/0003_auto_20240129_2025.py @@ -1,6 +1,7 @@ # Generated by Django 3.2.23 on 2024-01-29 20:25 import django.db.models.deletion -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/tests/testapp/facility_profile/migrations/0004_testmodel.py b/tests/testapp/facility_profile/migrations/0004_testmodel.py index 36e8bca6..2eb028f7 100644 --- a/tests/testapp/facility_profile/migrations/0004_testmodel.py +++ b/tests/testapp/facility_profile/migrations/0004_testmodel.py @@ -1,5 +1,6 @@ # Generated by Django 3.2.25 on 2025-09-22 23:23 -from django.db import migrations, models +from django.db import migrations +from django.db import models import morango.models.fields.uuids diff --git a/tests/testapp/facility_profile/migrations/0005_conditionallog.py b/tests/testapp/facility_profile/migrations/0005_conditionallog.py index 2b326658..a1d4c001 100644 --- a/tests/testapp/facility_profile/migrations/0005_conditionallog.py +++ b/tests/testapp/facility_profile/migrations/0005_conditionallog.py @@ -3,7 +3,8 @@ import django.db.models.deletion from django.conf import settings -from django.db import migrations, models +from django.db import migrations +from django.db import models import morango.models.fields.uuids diff --git a/tests/testapp/facility_profile/models.py b/tests/testapp/facility_profile/models.py index da1d6cab..3bf3cbef 100644 --- a/tests/testapp/facility_profile/models.py +++ b/tests/testapp/facility_profile/models.py @@ -1,6 +1,7 @@ import uuid -from django.contrib.auth.models import AbstractBaseUser, UserManager +from django.contrib.auth.models import AbstractBaseUser +from django.contrib.auth.models import UserManager from django.db import models from django.utils import timezone diff --git a/tests/testapp/testapp/urls.py b/tests/testapp/testapp/urls.py index 97712e08..f93743ef 100644 --- a/tests/testapp/testapp/urls.py +++ b/tests/testapp/testapp/urls.py @@ -14,7 +14,8 @@ 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ -from django.urls import include, path +from django.urls import include +from django.urls import path urlpatterns = [ path("", include("morango.urls")), diff --git a/tests/testapp/tests/helpers.py b/tests/testapp/tests/helpers.py index 94e9187b..55bc9467 100644 --- a/tests/testapp/tests/helpers.py +++ b/tests/testapp/tests/helpers.py @@ -10,23 +10,27 @@ from django.core.serializers.json import DjangoJSONEncoder from django.test.testcases import LiveServerTestCase from django.utils import timezone -from facility_profile.models import Facility, InteractionLog, MyUser, SummaryLog +from facility_profile.models import Facility +from facility_profile.models import InteractionLog +from facility_profile.models import MyUser +from facility_profile.models import SummaryLog from morango.api.serializers import BufferSerializer -from morango.models.core import ( - AbstractStore, - Buffer, - DatabaseIDModel, - InstanceIDModel, - RecordMaxCounter, - RecordMaxCounterBuffer, - Store, - SyncSession, - TransferSession, -) +from morango.models.core import AbstractStore +from morango.models.core import Buffer +from morango.models.core import DatabaseIDModel +from morango.models.core import InstanceIDModel +from morango.models.core import RecordMaxCounter +from morango.models.core import RecordMaxCounterBuffer +from morango.models.core import Store +from morango.models.core import SyncSession +from morango.models.core import TransferSession from morango.sync.context import SessionContext -from morango.sync.controller import MorangoProfileController, SessionController -from morango.sync.syncsession import NetworkSyncConnection, SyncSessionClient, TransferClient +from morango.sync.controller import MorangoProfileController +from morango.sync.controller import SessionController +from morango.sync.syncsession import NetworkSyncConnection +from morango.sync.syncsession import SyncSessionClient +from morango.sync.syncsession import TransferClient from .compat import EnvironmentVarGuard diff --git a/tests/testapp/tests/integration/test_signals.py b/tests/testapp/tests/integration/test_signals.py index 461a3113..abc34485 100644 --- a/tests/testapp/tests/integration/test_signals.py +++ b/tests/testapp/tests/integration/test_signals.py @@ -1,7 +1,8 @@ from django.test import TestCase from facility_profile.models import Facility -from morango.models.core import DeletedModels, InstanceIDModel +from morango.models.core import DeletedModels +from morango.models.core import InstanceIDModel from morango.sync.controller import MorangoProfileController from ..helpers import FacilityModelFactory diff --git a/tests/testapp/tests/integration/test_syncing_models.py b/tests/testapp/tests/integration/test_syncing_models.py index 6f8b4e35..904124f3 100644 --- a/tests/testapp/tests/integration/test_syncing_models.py +++ b/tests/testapp/tests/integration/test_syncing_models.py @@ -1,7 +1,9 @@ import json from django.test import TestCase -from facility_profile.models import Facility, MyUser, TestModel +from facility_profile.models import Facility +from facility_profile.models import MyUser +from facility_profile.models import TestModel from morango.models.core import Store from morango.models.manager import SyncableModelManager diff --git a/tests/testapp/tests/integration/test_syncsession.py b/tests/testapp/tests/integration/test_syncsession.py index c815e4c9..cc019328 100644 --- a/tests/testapp/tests/integration/test_syncsession.py +++ b/tests/testapp/tests/integration/test_syncsession.py @@ -11,13 +11,21 @@ import requests from django.conf import settings from django.test.testcases import TransactionTestCase -from facility_profile.models import InteractionLog, MyUser, SummaryLog -from requests.exceptions import RequestException, Timeout +from facility_profile.models import InteractionLog +from facility_profile.models import MyUser +from facility_profile.models import SummaryLog +from requests.exceptions import RequestException +from requests.exceptions import Timeout from testapp.settings import BASE_DIR from morango.errors import MorangoError -from morango.models.certificates import Certificate, Filter, Key, ScopeDefinition -from morango.models.core import Buffer, InstanceIDModel, TransferSession +from morango.models.certificates import Certificate +from morango.models.certificates import Filter +from morango.models.certificates import Key +from morango.models.certificates import ScopeDefinition +from morango.models.core import Buffer +from morango.models.core import InstanceIDModel +from morango.models.core import TransferSession from morango.sync.controller import MorangoProfileController from ..compat import EnvironmentVarGuard diff --git a/tests/testapp/tests/models/test_certificates.py b/tests/testapp/tests/models/test_certificates.py index 551dbd5c..a7b3289c 100644 --- a/tests/testapp/tests/models/test_certificates.py +++ b/tests/testapp/tests/models/test_certificates.py @@ -1,15 +1,17 @@ import json -from django.test import SimpleTestCase, TestCase - -from morango.errors import ( - CertificateIDInvalid, - CertificateProfileInvalid, - CertificateRootScopeInvalid, - CertificateScopeNotSubset, - CertificateSignatureInvalid, -) -from morango.models.certificates import Certificate, Filter, Key, ScopeDefinition +from django.test import SimpleTestCase +from django.test import TestCase + +from morango.errors import CertificateIDInvalid +from morango.errors import CertificateProfileInvalid +from morango.errors import CertificateRootScopeInvalid +from morango.errors import CertificateScopeNotSubset +from morango.errors import CertificateSignatureInvalid +from morango.models.certificates import Certificate +from morango.models.certificates import Filter +from morango.models.certificates import Key +from morango.models.certificates import ScopeDefinition class CertificateTestCaseMixin(object): diff --git a/tests/testapp/tests/models/test_core.py b/tests/testapp/tests/models/test_core.py index 2379aa66..66f1e1bb 100644 --- a/tests/testapp/tests/models/test_core.py +++ b/tests/testapp/tests/models/test_core.py @@ -3,16 +3,24 @@ import factory import mock from django.core.exceptions import ValidationError -from django.test import TestCase, override_settings +from django.test import override_settings +from django.test import TestCase from django.utils import timezone -from facility_profile.models import Facility, MyUser +from facility_profile.models import Facility +from facility_profile.models import MyUser -from morango.constants import transfer_stages, transfer_statuses +from morango.constants import transfer_stages +from morango.constants import transfer_statuses from morango.models.certificates import Filter -from morango.models.core import Buffer, DatabaseMaxCounter, Store, SyncSession, TransferSession +from morango.models.core import Buffer +from morango.models.core import DatabaseMaxCounter +from morango.models.core import Store +from morango.models.core import SyncSession +from morango.models.core import TransferSession from morango.sync.controller import MorangoProfileController -from ..helpers import RecordMaxCounterFactory, StoreFactory +from ..helpers import RecordMaxCounterFactory +from ..helpers import StoreFactory class DatabaseMaxCounterFactory(factory.django.DjangoModelFactory): diff --git a/tests/testapp/tests/models/test_fsic_utils.py b/tests/testapp/tests/models/test_fsic_utils.py index 2ebd73b9..60693f5a 100644 --- a/tests/testapp/tests/models/test_fsic_utils.py +++ b/tests/testapp/tests/models/test_fsic_utils.py @@ -1,11 +1,9 @@ from django.test import TestCase -from morango.models.fsic_utils import ( - calculate_directional_fsic_diff_v2, - chunk_fsic_v2, - expand_fsic_for_use, - remove_redundant_instance_counters, -) +from morango.models.fsic_utils import calculate_directional_fsic_diff_v2 +from morango.models.fsic_utils import chunk_fsic_v2 +from morango.models.fsic_utils import expand_fsic_for_use +from morango.models.fsic_utils import remove_redundant_instance_counters class TestFSICUtils(TestCase): diff --git a/tests/testapp/tests/sync/stream/test_core.py b/tests/testapp/tests/sync/stream/test_core.py index 62f9d5de..91394475 100644 --- a/tests/testapp/tests/sync/stream/test_core.py +++ b/tests/testapp/tests/sync/stream/test_core.py @@ -1,6 +1,12 @@ from django.test import SimpleTestCase -from morango.sync.stream.core import Buffer, FlatMap, Pipeline, Sink, Source, Transform, Unbuffer +from morango.sync.stream.core import Buffer +from morango.sync.stream.core import FlatMap +from morango.sync.stream.core import Pipeline +from morango.sync.stream.core import Sink +from morango.sync.stream.core import Source +from morango.sync.stream.core import Transform +from morango.sync.stream.core import Unbuffer class FakeSource(Source): diff --git a/tests/testapp/tests/sync/stream/test_serialize.py b/tests/testapp/tests/sync/stream/test_serialize.py index d1eb143e..daea5e33 100644 --- a/tests/testapp/tests/sync/stream/test_serialize.py +++ b/tests/testapp/tests/sync/stream/test_serialize.py @@ -3,18 +3,20 @@ import mock from django.db.models import Q -from django.test import SimpleTestCase, TestCase +from django.test import SimpleTestCase +from django.test import TestCase from morango.models.certificates import Filter -from morango.models.core import InstanceIDModel, RecordMaxCounter, Store, SyncableModel -from morango.sync.stream.serialize import ( - AppModelSource, - SelfRefOrderLookup, - SerializeTask, - StoreLookup, - StoreUpdate, - WriteSink, -) +from morango.models.core import InstanceIDModel +from morango.models.core import RecordMaxCounter +from morango.models.core import Store +from morango.models.core import SyncableModel +from morango.sync.stream.serialize import AppModelSource +from morango.sync.stream.serialize import SelfRefOrderLookup +from morango.sync.stream.serialize import SerializeTask +from morango.sync.stream.serialize import StoreLookup +from morango.sync.stream.serialize import StoreUpdate +from morango.sync.stream.serialize import WriteSink class SerializeTaskTestCase(SimpleTestCase): diff --git a/tests/testapp/tests/sync/test_context.py b/tests/testapp/tests/sync/test_context.py index d01b8bda..00d6d904 100644 --- a/tests/testapp/tests/sync/test_context.py +++ b/tests/testapp/tests/sync/test_context.py @@ -1,21 +1,23 @@ import pickle import mock -from django.test import SimpleTestCase, TestCase +from django.test import SimpleTestCase +from django.test import TestCase -from morango.constants import transfer_stages, transfer_statuses +from morango.constants import transfer_stages +from morango.constants import transfer_statuses from morango.errors import MorangoContextUpdateError from morango.models.certificates import Filter -from morango.models.core import SyncSession, TransferSession -from morango.sync.context import ( - CompositeSessionContext, - LocalSessionContext, - NetworkSessionContext, - SessionContext, -) +from morango.models.core import SyncSession +from morango.models.core import TransferSession +from morango.sync.context import CompositeSessionContext +from morango.sync.context import LocalSessionContext +from morango.sync.context import NetworkSessionContext +from morango.sync.context import SessionContext from morango.sync.controller import SessionController -from ..helpers import TestSessionContext, create_dummy_store_data +from ..helpers import create_dummy_store_data +from ..helpers import TestSessionContext class SessionContextTestCase(SimpleTestCase): diff --git a/tests/testapp/tests/sync/test_controller.py b/tests/testapp/tests/sync/test_controller.py index d0846e85..1de23018 100644 --- a/tests/testapp/tests/sync/test_controller.py +++ b/tests/testapp/tests/sync/test_controller.py @@ -4,16 +4,27 @@ import factory import mock -from django.test import SimpleTestCase, TestCase -from facility_profile.models import Facility, InteractionLog, MyUser, SummaryLog - -from morango.constants import transfer_stages, transfer_statuses +from django.test import SimpleTestCase +from django.test import TestCase +from facility_profile.models import Facility +from facility_profile.models import InteractionLog +from facility_profile.models import MyUser +from facility_profile.models import SummaryLog + +from morango.constants import transfer_stages +from morango.constants import transfer_statuses from morango.models.certificates import Filter -from morango.models.core import DeletedModels, InstanceIDModel, RecordMaxCounter, Store -from morango.sync.controller import MorangoProfileController, SessionController +from morango.models.core import DeletedModels +from morango.models.core import InstanceIDModel +from morango.models.core import RecordMaxCounter +from morango.models.core import Store +from morango.sync.controller import MorangoProfileController +from morango.sync.controller import SessionController from ..compat import EnvironmentVarGuard -from ..helpers import FacilityModelFactory, TestSessionContext, serialized_facility_factory +from ..helpers import FacilityModelFactory +from ..helpers import serialized_facility_factory +from ..helpers import TestSessionContext class StoreModelFacilityFactory(factory.django.DjangoModelFactory): diff --git a/tests/testapp/tests/sync/test_db.py b/tests/testapp/tests/sync/test_db.py index f6503e40..4882939f 100644 --- a/tests/testapp/tests/sync/test_db.py +++ b/tests/testapp/tests/sync/test_db.py @@ -5,11 +5,14 @@ import pytest from django.conf import settings from django.db import connection -from django.test import TransactionTestCase, override_settings +from django.test import override_settings +from django.test import TransactionTestCase from django.utils import timezone from morango.models.certificates import Filter -from morango.models.core import Store, SyncSession, TransferSession +from morango.models.core import Store +from morango.models.core import SyncSession +from morango.models.core import TransferSession from morango.sync.backends.utils import load_backend from morango.sync.db import begin_transaction diff --git a/tests/testapp/tests/sync/test_operations.py b/tests/testapp/tests/sync/test_operations.py index 140d7c32..2eb264d0 100644 --- a/tests/testapp/tests/sync/test_operations.py +++ b/tests/testapp/tests/sync/test_operations.py @@ -3,45 +3,48 @@ import mock from django.db import connection -from django.test import TestCase, override_settings +from django.test import override_settings +from django.test import TestCase from django.utils import timezone -from facility_profile.models import ConditionalLog, Facility, MyUser, SummaryLog +from facility_profile.models import ConditionalLog +from facility_profile.models import Facility +from facility_profile.models import MyUser +from facility_profile.models import SummaryLog from morango.constants import transfer_statuses -from morango.constants.capabilities import FSIC_V2_FORMAT, SELF_REF_ORDER +from morango.constants.capabilities import FSIC_V2_FORMAT +from morango.constants.capabilities import SELF_REF_ORDER from morango.errors import MorangoLimitExceeded from morango.models.certificates import Filter -from morango.models.core import ( - Buffer, - DatabaseIDModel, - DatabaseMaxCounter, - InstanceIDModel, - RecordMaxCounter, - RecordMaxCounterBuffer, - Store, - SyncSession, - TransferSession, -) +from morango.models.core import Buffer +from morango.models.core import DatabaseIDModel +from morango.models.core import DatabaseMaxCounter +from morango.models.core import InstanceIDModel +from morango.models.core import RecordMaxCounter +from morango.models.core import RecordMaxCounterBuffer +from morango.models.core import Store +from morango.models.core import SyncSession +from morango.models.core import TransferSession from morango.sync.backends.utils import load_backend from morango.sync.context import LocalSessionContext -from morango.sync.controller import MorangoProfileController, SessionController -from morango.sync.operations import ( - CleanupOperation, - InitializeOperation, - ProducerDequeueOperation, - ProducerQueueOperation, - ReceiverDequeueOperation, - ReceiverDeserializeOperation, - ReceiverQueueOperation, - _dequeue_into_store, - _deserialize_from_store, - _queue_into_buffer_v1, - _queue_into_buffer_v2, - _update_legacy_self_ref_order, -) +from morango.sync.controller import MorangoProfileController +from morango.sync.controller import SessionController +from morango.sync.operations import _dequeue_into_store +from morango.sync.operations import _deserialize_from_store +from morango.sync.operations import _queue_into_buffer_v1 +from morango.sync.operations import _queue_into_buffer_v2 +from morango.sync.operations import _update_legacy_self_ref_order +from morango.sync.operations import CleanupOperation +from morango.sync.operations import InitializeOperation +from morango.sync.operations import ProducerDequeueOperation +from morango.sync.operations import ProducerQueueOperation +from morango.sync.operations import ReceiverDequeueOperation +from morango.sync.operations import ReceiverDeserializeOperation +from morango.sync.operations import ReceiverQueueOperation from morango.sync.syncsession import TransferClient -from ..helpers import create_buffer_and_store_dummy_data, create_dummy_store_data +from ..helpers import create_buffer_and_store_dummy_data +from ..helpers import create_dummy_store_data DBBackend = load_backend(connection) diff --git a/tests/testapp/tests/sync/test_session.py b/tests/testapp/tests/sync/test_session.py index 1dffdc16..439bbb7a 100644 --- a/tests/testapp/tests/sync/test_session.py +++ b/tests/testapp/tests/sync/test_session.py @@ -1,8 +1,10 @@ import mock from django.test import TestCase -from requests.exceptions import HTTPError, RequestException +from requests.exceptions import HTTPError +from requests.exceptions import RequestException -from morango.sync.session import SessionWrapper, _length_of_headers +from morango.sync.session import _length_of_headers +from morango.sync.session import SessionWrapper class SessionWrapperTestCase(TestCase): diff --git a/tests/testapp/tests/sync/test_syncsession.py b/tests/testapp/tests/sync/test_syncsession.py index 120a90d9..abd9fa68 100644 --- a/tests/testapp/tests/sync/test_syncsession.py +++ b/tests/testapp/tests/sync/test_syncsession.py @@ -7,29 +7,31 @@ from requests.exceptions import HTTPError from morango.api.serializers import CertificateSerializer -from morango.constants import transfer_stages, transfer_statuses +from morango.constants import transfer_stages +from morango.constants import transfer_statuses from morango.constants.capabilities import ALLOW_CERTIFICATE_PUSHING -from morango.errors import ( - CertificateSignatureInvalid, - MorangoError, - MorangoResumeSyncError, - MorangoServerDoesNotAllowNewCertPush, -) -from morango.models.certificates import Certificate, Filter, Key, ScopeDefinition +from morango.errors import CertificateSignatureInvalid +from morango.errors import MorangoError +from morango.errors import MorangoResumeSyncError +from morango.errors import MorangoServerDoesNotAllowNewCertPush +from morango.models.certificates import Certificate +from morango.models.certificates import Filter +from morango.models.certificates import Key +from morango.models.certificates import ScopeDefinition from morango.models.core import SyncSession from morango.models.fields.crypto import SharedKey -from morango.sync.context import LocalSessionContext, NetworkSessionContext +from morango.sync.context import LocalSessionContext +from morango.sync.context import NetworkSessionContext from morango.sync.controller import MorangoProfileController from morango.sync.session import SessionWrapper -from morango.sync.syncsession import ( - NetworkSyncConnection, - PullClient, - PushClient, - SyncSessionClient, - TransferClient, -) - -from ..helpers import BaseClientTestCase, BaseTransferClientTestCase +from morango.sync.syncsession import NetworkSyncConnection +from morango.sync.syncsession import PullClient +from morango.sync.syncsession import PushClient +from morango.sync.syncsession import SyncSessionClient +from morango.sync.syncsession import TransferClient + +from ..helpers import BaseClientTestCase +from ..helpers import BaseTransferClientTestCase def mock_patch_decorator(func): diff --git a/tests/testapp/tests/sync/test_utils.py b/tests/testapp/tests/sync/test_utils.py index 6077ee77..514118c0 100644 --- a/tests/testapp/tests/sync/test_utils.py +++ b/tests/testapp/tests/sync/test_utils.py @@ -1,7 +1,8 @@ import mock from django.test import TestCase -from morango.sync.utils import SyncSignal, SyncSignalGroup +from morango.sync.utils import SyncSignal +from morango.sync.utils import SyncSignalGroup class SyncSignalTestCase(TestCase): diff --git a/tests/testapp/tests/test_api.py b/tests/testapp/tests/test_api.py index 65adb3a6..3bd64d2b 100644 --- a/tests/testapp/tests/test_api.py +++ b/tests/testapp/tests/test_api.py @@ -3,7 +3,8 @@ from base64 import encodebytes as b64encode from django.db import connection -from django.test.utils import CaptureQueriesContext, override_settings +from django.test.utils import CaptureQueriesContext +from django.test.utils import override_settings from django.urls import reverse from django.urls.exceptions import NoReverseMatch from django.utils import timezone @@ -11,17 +12,21 @@ from facility_profile.models import MyUser from rest_framework.test import APITestCase -from morango.api.serializers import BufferSerializer, CertificateSerializer, InstanceIDSerializer -from morango.constants import transfer_stages, transfer_statuses -from morango.models.certificates import Certificate, Key, Nonce, ScopeDefinition -from morango.models.core import ( - Buffer, - DatabaseMaxCounter, - InstanceIDModel, - RecordMaxCounterBuffer, - SyncSession, - TransferSession, -) +from morango.api.serializers import BufferSerializer +from morango.api.serializers import CertificateSerializer +from morango.api.serializers import InstanceIDSerializer +from morango.constants import transfer_stages +from morango.constants import transfer_statuses +from morango.models.certificates import Certificate +from morango.models.certificates import Key +from morango.models.certificates import Nonce +from morango.models.certificates import ScopeDefinition +from morango.models.core import Buffer +from morango.models.core import DatabaseMaxCounter +from morango.models.core import InstanceIDModel +from morango.models.core import RecordMaxCounterBuffer +from morango.models.core import SyncSession +from morango.models.core import TransferSession from morango.models.fields.crypto import SharedKey from morango.registry import syncable_models from morango.sync.syncsession import compress_string diff --git a/tests/testapp/tests/test_management_commands.py b/tests/testapp/tests/test_management_commands.py index f93be95b..85b48b8b 100644 --- a/tests/testapp/tests/test_management_commands.py +++ b/tests/testapp/tests/test_management_commands.py @@ -5,7 +5,8 @@ from django.test import TestCase from django.utils import timezone -from morango.models.core import SyncSession, TransferSession +from morango.models.core import SyncSession +from morango.models.core import TransferSession from .helpers import create_buffer_and_store_dummy_data diff --git a/tests/testapp/tests/test_utils.py b/tests/testapp/tests/test_utils.py index 9440b702..d7c4e3b1 100644 --- a/tests/testapp/tests/test_utils.py +++ b/tests/testapp/tests/test_utils.py @@ -5,31 +5,26 @@ from django.db import IntegrityError from django.http.request import HttpRequest from django.test.testcases import SimpleTestCase -from facility_profile.models import Facility, MyUser +from facility_profile.models import Facility +from facility_profile.models import MyUser from requests import Request from morango.constants import transfer_stages -from morango.constants.capabilities import ( - ALLOW_CERTIFICATE_PUSHING, - ASYNC_OPERATIONS, - FSIC_V2_FORMAT, - SELF_REF_ORDER, -) -from morango.errors import ( - MorangoDatabaseError, -) -from morango.utils import ( - CAPABILITIES_CLIENT_HEADER, - SETTINGS, - _posix_pid_exists, - _windows_pid_exists, - exception_path, - get_capabilities, - parse_capabilities_from_server_request, - pid_exists, - self_referential_fk, - serialize_capabilities_to_client_request, -) +from morango.constants.capabilities import ALLOW_CERTIFICATE_PUSHING +from morango.constants.capabilities import ASYNC_OPERATIONS +from morango.constants.capabilities import FSIC_V2_FORMAT +from morango.constants.capabilities import SELF_REF_ORDER +from morango.errors import MorangoDatabaseError +from morango.utils import _posix_pid_exists +from morango.utils import _windows_pid_exists +from morango.utils import CAPABILITIES_CLIENT_HEADER +from morango.utils import exception_path +from morango.utils import get_capabilities +from morango.utils import parse_capabilities_from_server_request +from morango.utils import pid_exists +from morango.utils import self_referential_fk +from morango.utils import serialize_capabilities_to_client_request +from morango.utils import SETTINGS class SettingsTestCase(SimpleTestCase): diff --git a/tests/testapp/tests/test_uuid_utilities.py b/tests/testapp/tests/test_uuid_utilities.py index 892b6764..5f9df151 100644 --- a/tests/testapp/tests/test_uuid_utilities.py +++ b/tests/testapp/tests/test_uuid_utilities.py @@ -3,17 +3,18 @@ import mock from django.test import TestCase -from facility_profile.models import Facility, InteractionLog, MyUser +from facility_profile.models import Facility +from facility_profile.models import InteractionLog +from facility_profile.models import MyUser from morango.errors import InvalidMorangoSourceId -from morango.models.core import DatabaseIDModel, InstanceIDModel +from morango.models.core import DatabaseIDModel +from morango.models.core import InstanceIDModel from morango.models.fields.uuids import sha2_uuid -from morango.models.utils import ( - _calculate_0_4_uuid, - get_0_4_system_parameters, - get_0_5_mac_address, - get_0_5_system_id, -) +from morango.models.utils import _calculate_0_4_uuid +from morango.models.utils import get_0_4_system_parameters +from morango.models.utils import get_0_5_mac_address +from morango.models.utils import get_0_5_system_id from .compat import EnvironmentVarGuard diff --git a/tox.ini b/tox.ini index 07a06e87..a62c1e2a 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ allowlist_externals= deps = cryptography40.0.2: cryptography==40.0.2 -extras = +dependency_groups = test setenv = @@ -22,9 +22,11 @@ commands = python -O -m pytest {posargs: --color=no} [testenv:postgres] -extras = +dependency_groups = test +extras = postgres + accelerated setenv = PYTHONPATH = {toxinidir}:{toxinidir}/tests/testapp @@ -34,7 +36,7 @@ commands = python -O -m pytest {posargs: --color=no} [testenv:windows] -extras = +dependency_groups = test setenv = diff --git a/uv.lock b/uv.lock index c68ed40e..f524dfc8 100644 --- a/uv.lock +++ b/uv.lock @@ -13,7 +13,7 @@ resolution-markers = [ ] [options] -exclude-newer = "2026-03-26T07:53:50.714888877Z" +exclude-newer = "2026-06-05T14:46:36.610476653Z" exclude-newer-span = "P7D" [[package]] @@ -1660,8 +1660,26 @@ accelerated = [ { name = "cryptography" }, { name = "m2crypto" }, ] +postgres = [ + { name = "cryptography" }, + { name = "m2crypto" }, + { name = "psycopg2-binary", version = "2.9.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.7'" }, + { name = "psycopg2-binary", version = "2.9.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.7'" }, +] + +[package.dev-dependencies] dev = [ + { name = "factory-boy", version = "3.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.7'" }, + { name = "factory-boy", version = "3.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.7.*'" }, + { name = "factory-boy", version = "3.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, + { name = "mock" }, + { name = "more-itertools", version = "8.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.7'" }, + { name = "more-itertools", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.7.*'" }, + { name = "more-itertools", version = "10.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, { name = "prek", marker = "python_full_version >= '3.8'" }, + { name = "pytest", version = "7.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.7'" }, + { name = "pytest", version = "7.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.7'" }, + { name = "pytest-django" }, { name = "tox", version = "3.14.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "tox", version = "4.30.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, { name = "tox", version = "4.50.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, @@ -1694,12 +1712,6 @@ docs = [ { name = "watchdog", version = "4.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, { name = "watchdog", version = "6.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, ] -postgres = [ - { name = "cryptography" }, - { name = "m2crypto" }, - { name = "psycopg2-binary", version = "2.9.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.7'" }, - { name = "psycopg2-binary", version = "2.9.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.7'" }, -] test = [ { name = "factory-boy", version = "3.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.7'" }, { name = "factory-boy", version = "3.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.7.*'" }, @@ -1718,37 +1730,50 @@ requires-dist = [ { name = "cryptography", marker = "extra == 'accelerated'", specifier = "==40.0.2" }, { name = "cryptography", marker = "extra == 'postgres'", specifier = "==40.0.2" }, { name = "django", specifier = ">=3,<4" }, - { name = "django", marker = "extra == 'docs'", specifier = "==3.2.25" }, { name = "django-ipware", specifier = "==4.0.2" }, { name = "django-mptt", specifier = ">0.10.0" }, - { name = "django-mptt", marker = "extra == 'docs'", specifier = ">=0.14.0,<1" }, { name = "djangorestframework", specifier = ">3.10" }, - { name = "djangorestframework", marker = "extra == 'docs'", specifier = "==3.14.0" }, - { name = "factory-boy", marker = "extra == 'test'", specifier = ">=3.0,<4" }, { name = "ifcfg" }, - { name = "ifcfg", marker = "extra == 'docs'", specifier = "==0.24" }, { name = "m2crypto", marker = "extra == 'accelerated'", specifier = "==0.41.0" }, { name = "m2crypto", marker = "extra == 'postgres'", specifier = "==0.41.0" }, - { name = "mock", marker = "extra == 'test'", specifier = ">=4.0,<6" }, - { name = "more-itertools", marker = "extra == 'test'", specifier = "<=10.0.0" }, - { name = "prek", marker = "python_full_version >= '3.8' and extra == 'dev'", specifier = ">=0.3.6" }, { name = "psycopg2-binary", marker = "extra == 'postgres'", specifier = ">=2.9.8,<=2.9.9" }, - { name = "pytest", marker = "extra == 'test'", specifier = ">=6.2.5,<8" }, - { name = "pytest-django", marker = "extra == 'test'", specifier = "==4.5.2" }, { name = "requests" }, { name = "rsa", specifier = "<4.10" }, - { name = "rsa", marker = "extra == 'docs'", specifier = "==3.4.2" }, - { name = "sphinx", marker = "extra == 'docs'" }, - { name = "sphinx-autobuild", marker = "extra == 'docs'" }, - { name = "sphinx-intl", marker = "extra == 'docs'" }, - { name = "sphinx-notfound-page", marker = "extra == 'docs'" }, - { name = "sphinx-rtd-theme", marker = "extra == 'docs'" }, - { name = "tox", marker = "python_full_version >= '3.9' and extra == 'dev'", specifier = ">=4" }, - { name = "tox", marker = "python_full_version < '3.9' and extra == 'dev'", specifier = "<4" }, - { name = "tox-uv", marker = "python_full_version >= '3.9' and extra == 'dev'", specifier = ">=1.0" }, - { name = "watchdog", marker = "extra == 'docs'" }, -] -provides-extras = ["test", "dev", "docs", "postgres", "accelerated"] +] +provides-extras = ["postgres", "accelerated"] + +[package.metadata.requires-dev] +dev = [ + { name = "factory-boy", specifier = ">=3.0,<4" }, + { name = "mock", specifier = ">=4.0,<6" }, + { name = "more-itertools", specifier = "<=10.0.0" }, + { name = "prek", marker = "python_full_version >= '3.8'", specifier = ">=0.3.6" }, + { name = "pytest", specifier = ">=6.2.5,<8" }, + { name = "pytest-django", specifier = "==4.5.2" }, + { name = "tox", marker = "python_full_version < '3.9'", specifier = "<4" }, + { name = "tox", marker = "python_full_version >= '3.9'", specifier = ">=4" }, + { name = "tox-uv", marker = "python_full_version >= '3.9'", specifier = ">=1.0" }, +] +docs = [ + { name = "django", specifier = "==3.2.25" }, + { name = "django-mptt", specifier = ">=0.14.0,<1" }, + { name = "djangorestframework", specifier = "==3.14.0" }, + { name = "ifcfg", specifier = "==0.24" }, + { name = "rsa", specifier = "==3.4.2" }, + { name = "sphinx" }, + { name = "sphinx-autobuild" }, + { name = "sphinx-intl" }, + { name = "sphinx-notfound-page" }, + { name = "sphinx-rtd-theme" }, + { name = "watchdog" }, +] +test = [ + { name = "factory-boy", specifier = ">=3.0,<4" }, + { name = "mock", specifier = ">=4.0,<6" }, + { name = "more-itertools", specifier = "<=10.0.0" }, + { name = "pytest", specifier = ">=6.2.5,<8" }, + { name = "pytest-django", specifier = "==4.5.2" }, +] [[package]] name = "more-itertools"