diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml old mode 100644 new mode 100755 index 3377e3eb..434e0db5 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -9,7 +9,7 @@ on: - 'v*' env: - PYTHON_VERSION: 3.14 + PYTHON_VERSION: "3.13" jobs: build: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml old mode 100644 new mode 100755 index 57804c99..00c64e9a --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: matrix: os: [ubuntu-22.04] # os: [ubuntu-22.04, macos-latest, windows-latest] - python: [3.14] + python: ["3.13"] steps: - uses: actions/checkout@v4 @@ -38,7 +38,7 @@ jobs: - name: Setup PDM uses: pdm-project/setup-pdm@v3 with: - python-version: '3.14' + python-version: '3.13' cache: true ### Install Python & JS Dependencies diff --git a/archivebox/api/migrations/0002_alter_outboundwebhook_options_and_more.py b/archivebox/api/migrations/0002_alter_outboundwebhook_options_and_more.py old mode 100644 new mode 100755 index e2770792..5753f727 --- a/archivebox/api/migrations/0002_alter_outboundwebhook_options_and_more.py +++ b/archivebox/api/migrations/0002_alter_outboundwebhook_options_and_more.py @@ -3,7 +3,7 @@ import django.utils.timezone import signal_webhooks.fields import signal_webhooks.utils -import uuid +from archivebox import uuid_compat from django.conf import settings from django.db import migrations, models @@ -39,7 +39,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='apitoken', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), migrations.AlterField( model_name='outboundwebhook', @@ -69,7 +69,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='outboundwebhook', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), migrations.AlterField( model_name='outboundwebhook', diff --git a/archivebox/api/models.py b/archivebox/api/models.py old mode 100644 new mode 100755 index 41614074..17dff7bb --- a/archivebox/api/models.py +++ b/archivebox/api/models.py @@ -1,7 +1,7 @@ __package__ = 'archivebox.api' import secrets -from uuid import uuid7 +from archivebox.uuid_compat import uuid7 from datetime import timedelta from django.conf import settings diff --git a/archivebox/base_models/models.py b/archivebox/base_models/models.py old mode 100644 new mode 100755 index dafa428f..b238f75d --- a/archivebox/base_models/models.py +++ b/archivebox/base_models/models.py @@ -5,7 +5,8 @@ __package__ = 'archivebox.base_models' import io import csv import json -from uuid import uuid7, UUID +from uuid import UUID +from archivebox.uuid_compat import uuid7 from typing import Any, Iterable, ClassVar from pathlib import Path diff --git a/archivebox/core/migrations/0026_remove_archiveresult_output_dir_and_more.py b/archivebox/core/migrations/0026_remove_archiveresult_output_dir_and_more.py old mode 100644 new mode 100755 index dfead5b3..7bd1313f --- a/archivebox/core/migrations/0026_remove_archiveresult_output_dir_and_more.py +++ b/archivebox/core/migrations/0026_remove_archiveresult_output_dir_and_more.py @@ -3,7 +3,7 @@ import archivebox.base_models.models import django.db.models.deletion import django.utils.timezone -import uuid +from archivebox import uuid_compat from django.conf import settings from django.db import migrations, models @@ -52,7 +52,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='archiveresult', name='uuid', - field=models.UUIDField(blank=True, db_index=True, default=uuid.uuid7, null=True, unique=True), + field=models.UUIDField(blank=True, db_index=True, default=uuid_compat.uuid7, null=True, unique=True), ), migrations.AlterField( model_name='snapshot', @@ -77,7 +77,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='snapshot', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), # migrations.AlterField( # model_name='snapshot', diff --git a/archivebox/core/models.py b/archivebox/core/models.py old mode 100644 new mode 100755 index 1af5b972..30786abf --- a/archivebox/core/models.py +++ b/archivebox/core/models.py @@ -1,7 +1,7 @@ __package__ = 'archivebox.core' from typing import Optional, Dict, Iterable, Any, List, TYPE_CHECKING -from uuid import uuid7 +from archivebox.uuid_compat import uuid7 from datetime import datetime, timedelta from django_stubs_ext.db.models import TypedModelMeta diff --git a/archivebox/crawls/migrations/0002_drop_seed_model.py b/archivebox/crawls/migrations/0002_drop_seed_model.py old mode 100644 new mode 100755 index f0a66af5..3973067c --- a/archivebox/crawls/migrations/0002_drop_seed_model.py +++ b/archivebox/crawls/migrations/0002_drop_seed_model.py @@ -3,7 +3,7 @@ import archivebox.base_models.models import django.db.models.deletion import pathlib -import uuid +from archivebox import uuid_compat from django.conf import settings from django.db import migrations, models @@ -33,7 +33,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='crawl', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), migrations.AlterField( model_name='crawl', @@ -53,7 +53,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='crawlschedule', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), migrations.DeleteModel( name='Seed', diff --git a/archivebox/crawls/models.py b/archivebox/crawls/models.py old mode 100644 new mode 100755 index 9f11b1c4..f4ec1aae --- a/archivebox/crawls/models.py +++ b/archivebox/crawls/models.py @@ -1,7 +1,7 @@ __package__ = 'archivebox.crawls' from typing import TYPE_CHECKING, Iterable -from uuid import uuid7 +from archivebox.uuid_compat import uuid7 from pathlib import Path from django.db import models diff --git a/archivebox/machine/migrations/0002_alter_dependency_bin_name_and_more.py b/archivebox/machine/migrations/0002_alter_dependency_bin_name_and_more.py old mode 100644 new mode 100755 index 6df9a423..9e512f0a --- a/archivebox/machine/migrations/0002_alter_dependency_bin_name_and_more.py +++ b/archivebox/machine/migrations/0002_alter_dependency_bin_name_and_more.py @@ -1,7 +1,7 @@ # Generated by Django 6.0 on 2025-12-25 09:34 import django.db.models.deletion -import uuid +from archivebox import uuid_compat from django.db import migrations, models @@ -35,7 +35,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='dependency', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), migrations.AlterField( model_name='installedbinary', @@ -45,7 +45,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='installedbinary', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), migrations.AlterField( model_name='machine', @@ -55,11 +55,11 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='machine', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), migrations.AlterField( model_name='networkinterface', name='id', - field=models.UUIDField(default=uuid.uuid7, editable=False, primary_key=True, serialize=False, unique=True), + field=models.UUIDField(default=uuid_compat.uuid7, editable=False, primary_key=True, serialize=False, unique=True), ), ] diff --git a/archivebox/machine/models.py b/archivebox/machine/models.py old mode 100644 new mode 100755 index 89e1f722..82733f07 --- a/archivebox/machine/models.py +++ b/archivebox/machine/models.py @@ -1,7 +1,7 @@ __package__ = 'archivebox.machine' import socket -from uuid import uuid7 +from archivebox.uuid_compat import uuid7 from datetime import timedelta from django.db import models diff --git a/archivebox/tests/tests_migrations.py b/archivebox/tests/tests_migrations.py old mode 100644 new mode 100755 diff --git a/archivebox/uuid_compat.py b/archivebox/uuid_compat.py new file mode 100755 index 00000000..00af61f5 --- /dev/null +++ b/archivebox/uuid_compat.py @@ -0,0 +1,19 @@ +"""UUID7 compatibility layer for Python 3.13+ + +Python 3.14+ has native uuid7 support. For Python 3.13, we use uuid_extensions. +""" + +import sys + +if sys.version_info >= (3, 14): + from uuid import uuid7 +else: + try: + from uuid_extensions import uuid7 + except ImportError: + raise ImportError( + "uuid_extensions package is required for Python <3.14. " + "Install it with: pip install uuid_extensions" + ) + +__all__ = ['uuid7'] diff --git a/bin/lock_pkgs.sh b/bin/lock_pkgs.sh index c3d1e88b..7a33d474 100755 --- a/bin/lock_pkgs.sh +++ b/bin/lock_pkgs.sh @@ -45,7 +45,7 @@ echo echo echo "[+] Generating dev & prod requirements.txt & pdm.lock from pyproject.toml..." -uv venv --allow-existing --python 3.14 +uv venv --allow-existing --python 3.13 source .venv/bin/activate echo echo "pyproject.toml: archivebox $(grep 'version = ' pyproject.toml | head -n 1 | awk '{print $3}' | jq -r)" diff --git a/pyproject.toml b/pyproject.toml old mode 100644 new mode 100755 index deb3f7df..6a0ca1b2 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "archivebox" version = "0.9.0rc1" -requires-python = ">=3.14" +requires-python = ">=3.13" description = "Self-hosted internet archiving solution." authors = [{name = "Nick Sweeting", email = "pyproject.toml@archivebox.io"}] license = {text = "MIT"} @@ -22,6 +22,7 @@ classifiers = [ "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Indexing/Search", @@ -92,6 +93,9 @@ dependencies = [ ### Binary/Package Management "abx-pkg>=0.1.0", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm + + ### UUID7 backport for Python <3.14 + "uuid7>=0.1.0; python_version < '3.14'", # for: uuid7 support on Python 3.13 (provides uuid_extensions module) ] [project.optional-dependencies] @@ -161,7 +165,7 @@ dev-dependencies = [ ] [tool.uv.pip] -python-version = "3.14" +python-version = "3.13" # compile-bytecode = true [build-system] @@ -175,7 +179,7 @@ package-dir = {"archivebox" = "archivebox"} [tool.ruff] line-length = 140 -target-version = "py314" +target-version = "py313" src = ["archivebox"] exclude = ["*.pyi", "typings/", "migrations/"] @@ -220,7 +224,7 @@ venv = ".venv" # defineConstant = { DEBUG = true } reportMissingImports = true reportMissingTypeStubs = false -pythonVersion = "3.14" +pythonVersion = "3.13" pythonPlatform = "Linux"