diff --git a/dje/tests/test_two_factor.py b/dje/tests/test_two_factor.py index e20a3ad8..53210842 100644 --- a/dje/tests/test_two_factor.py +++ b/dje/tests/test_two_factor.py @@ -11,12 +11,13 @@ from django.urls import reverse import django_otp -from django_otp.forms import OTPTokenForm from django_otp.oath import totp as oauth_totp from django_otp.plugins.otp_totp.models import TOTPDevice from dje.models import Dataspace from dje.tests import create_user +from dje.two_factor import TwoFactorDisableForm +from dje.two_factor import TwoFactorVerifyForm class TwoFactorAuthenticationTestCase(TestCase): @@ -132,7 +133,7 @@ def test_two_factor_authentication_disable_2fa(self): response = self.client.post(self.tfa_disable_url, data=data) self.assertContains(response, "Please enter your OTP token.") - device_form_value = OTPTokenForm.device_choices(self.user)[0][0] + device_form_value = device.persistent_id data = {"otp_token": "123456", "otp_device": device_form_value} response = self.client.post(self.tfa_disable_url, data=data) form_error = "Invalid token. Please make sure you have entered it correctly." @@ -178,7 +179,7 @@ def test_two_factor_authentication_login_with_2fa(self): self.assertContains(response, "Please enter your OTP token.") valid_token = self._get_valid_token(device.bin_key) - device_form_value = OTPTokenForm.device_choices(self.user)[0][0] + device_form_value = device.persistent_id data = { "otp_token": valid_token, "otp_device": device_form_value, @@ -190,3 +191,12 @@ def test_two_factor_authentication_login_with_2fa(self): self.assertIn("_auth_user_id", session_keys) self.assertIn("_auth_user_hash", session_keys) self.assertIn("otp_device_id", session_keys) + + def test_two_factor_authentication_token_form_preselects_user_device(self): + device = self._create_device(self.user) + expected = f'' + + for form_class in [TwoFactorDisableForm, TwoFactorVerifyForm]: + form = form_class(user=self.user) + self.assertEqual(device.persistent_id, form.fields["otp_device"].initial) + self.assertInHTML(expected, str(form["otp_device"])) diff --git a/dje/two_factor.py b/dje/two_factor.py index 11cbdb8a..c598fc6f 100644 --- a/dje/two_factor.py +++ b/dje/two_factor.py @@ -139,7 +139,21 @@ def helper(self): return helper -class TwoFactorDisableForm(OTPTokenForm): +class TwoFactorTokenForm(OTPTokenForm): + """ + Preselect the user device: the `otp_device` select is hidden and its first + choice is blank. + """ + + def __init__(self, user, *args, **kwargs): + super().__init__(user, *args, **kwargs) + + user_device = next(django_otp.devices_for_user(user), None) + if user_device: + self.fields["otp_device"].initial = user_device.persistent_id + + +class TwoFactorDisableForm(TwoFactorTokenForm): @property def helper(self): helper = FormHelper() @@ -168,7 +182,7 @@ def helper(self): return helper -class TwoFactorVerifyForm(OTPTokenForm): +class TwoFactorVerifyForm(TwoFactorTokenForm): """Verify that the user provided `otp_token` is valid.""" @property diff --git a/notification/tests/test_models.py b/notification/tests/test_models.py index 3c9c39c7..e2770c89 100644 --- a/notification/tests/test_models.py +++ b/notification/tests/test_models.py @@ -97,7 +97,11 @@ def test_webhook_subscription_deliver_inactive_returns_false(self, mock_post): @patch("requests.post") def test_webhook_subscription_deliver_request_exception_saves_error(self, mock_post): mock_post.side_effect = req.exceptions.ConnectionError("Connection refused") - delivery = self.webhook.deliver(None, payload_override={"key": "val"}) + with self.assertLogs("aboutcode.notifications", level="ERROR") as captured: + delivery = self.webhook.deliver(None, payload_override={"key": "val"}) + self.assertEqual( + ["Connection refused"], [record.getMessage() for record in captured.records] + ) self.assertIsNotNone(delivery) self.assertFalse(delivery.delivered) self.assertIn("Connection refused", delivery.delivery_error) diff --git a/pyproject.toml b/pyproject.toml index 6ed93d9e..237fa739 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ "setuptools==84.0.0", "packaging==26.3", # Django - "django==6.1.1", + "django==6.1.2", "asgiref==3.12.1", "typing-extensions==4.16.0", "sqlparse==0.6.0", @@ -42,7 +42,7 @@ dependencies = [ "django-crispy-forms==2.7", "crispy-bootstrap5==2026.9", "django-grappelli==5.0.0", - "django-filter==26.1", + "django-filter==26.2", "django-registration==5.2.1", "confusable_homoglyphs==3.3.1", "django-guardian==3.5.0", @@ -54,16 +54,18 @@ dependencies = [ "altcha==1.0.0", "django-altcha==1.0.0", # REST API - "djangorestframework==3.18.1", + "djangorestframework==3.18.3", # API documentation + # Do not upgrade: 1.21.17+ requires swagger-spec-validator, which pulls jsonschema, + # referencing, rpds-py, jsonschema-specifications, and importlib-resources. "drf-yasg==1.21.15", "uritemplate==4.2.0", "inflection==0.5.1", - "pytz==2026.4", + "pytz==2026.5", # Track failed login attempts "django-axes==8.3.1", # Multi-factor authentication - "django-otp==1.7.3", + "django-otp==1.7.4", "qrcode==8.2", # Database "psycopg==3.3.6", @@ -72,12 +74,12 @@ dependencies = [ # Antivirus "clamd==1.0.2", # Testing - "model-bakery==1.24.1", + "model-bakery==1.24.2", # Task queue "rq==2.12.0", "croniter==6.2.4", "django-rq==4.2.0", - "fakeredis==2.38.0", + "fakeredis==2.39.0", # Libs "certifi==2026.7.22", "urllib3==2.8.0", @@ -85,7 +87,7 @@ dependencies = [ "six==1.17.0", "requests==2.34.2", "idna==3.20", - "charset-normalizer==3.5.1", + "charset-normalizer==3.5.2", "PyYAML==6.0.3", "XlsxWriter==3.2.9", # Markdown @@ -111,7 +113,7 @@ dependencies = [ "attrs==26.1.0", "click==8.5.0", "Jinja2==3.1.6", - "MarkupSafe==3.0.3", + "markupsafe==3.0.4", "saneyaml==0.6.1", "openpyxl==3.1.5", "et-xmlfile==2.0.0", @@ -124,14 +126,14 @@ dependencies = [ "sortedcontainers==2.4.0", "py-serializable==2.1.0", # CSAF - "pydantic==2.13.5", - "pydantic-core==2.46.5", + "pydantic==2.14.1", + "pydantic-core==2.50.1", "typing-inspection==0.4.4", "annotated-types==0.8.0", # OpenVEX - "msgspec==0.21.1", + "msgspec==0.22.0", # OpenDocument Format - "odfdo==3.26.3", + "odfdo==3.27.1", "lxml==6.1.3", ] diff --git a/thirdparty/dist/charset_normalizer-3.5.1-cp314-cp314-macosx_10_15_universal2.whl b/thirdparty/dist/charset_normalizer-3.5.1-cp314-cp314-macosx_10_15_universal2.whl deleted file mode 100644 index 66a2b416..00000000 Binary files a/thirdparty/dist/charset_normalizer-3.5.1-cp314-cp314-macosx_10_15_universal2.whl and /dev/null differ diff --git a/thirdparty/dist/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/thirdparty/dist/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 5c639625..00000000 Binary files a/thirdparty/dist/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/thirdparty/dist/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl b/thirdparty/dist/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl new file mode 100644 index 00000000..1e677344 Binary files /dev/null and b/thirdparty/dist/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl differ diff --git a/thirdparty/dist/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/thirdparty/dist/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 00000000..7e41beee Binary files /dev/null and b/thirdparty/dist/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/thirdparty/dist/django-6.1.1-py3-none-any.whl b/thirdparty/dist/django-6.1.2-py3-none-any.whl similarity index 88% rename from thirdparty/dist/django-6.1.1-py3-none-any.whl rename to thirdparty/dist/django-6.1.2-py3-none-any.whl index de7d3f0b..a1e641c1 100644 Binary files a/thirdparty/dist/django-6.1.1-py3-none-any.whl and b/thirdparty/dist/django-6.1.2-py3-none-any.whl differ diff --git a/thirdparty/dist/django_filter-26.1-py3-none-any.whl b/thirdparty/dist/django_filter-26.2-py3-none-any.whl similarity index 87% rename from thirdparty/dist/django_filter-26.1-py3-none-any.whl rename to thirdparty/dist/django_filter-26.2-py3-none-any.whl index 322faff5..1a7727a9 100644 Binary files a/thirdparty/dist/django_filter-26.1-py3-none-any.whl and b/thirdparty/dist/django_filter-26.2-py3-none-any.whl differ diff --git a/thirdparty/dist/django_otp-1.7.3-py3-none-any.whl b/thirdparty/dist/django_otp-1.7.4-py3-none-any.whl similarity index 78% rename from thirdparty/dist/django_otp-1.7.3-py3-none-any.whl rename to thirdparty/dist/django_otp-1.7.4-py3-none-any.whl index da8c2cfe..09941247 100644 Binary files a/thirdparty/dist/django_otp-1.7.3-py3-none-any.whl and b/thirdparty/dist/django_otp-1.7.4-py3-none-any.whl differ diff --git a/thirdparty/dist/djangorestframework-3.18.1-py3-none-any.whl b/thirdparty/dist/djangorestframework-3.18.3-py3-none-any.whl similarity index 90% rename from thirdparty/dist/djangorestframework-3.18.1-py3-none-any.whl rename to thirdparty/dist/djangorestframework-3.18.3-py3-none-any.whl index 65caa86e..100e5c56 100644 Binary files a/thirdparty/dist/djangorestframework-3.18.1-py3-none-any.whl and b/thirdparty/dist/djangorestframework-3.18.3-py3-none-any.whl differ diff --git a/thirdparty/dist/fakeredis-2.38.0-py3-none-any.whl b/thirdparty/dist/fakeredis-2.38.0-py3-none-any.whl deleted file mode 100644 index b71d4646..00000000 Binary files a/thirdparty/dist/fakeredis-2.38.0-py3-none-any.whl and /dev/null differ diff --git a/thirdparty/dist/fakeredis-2.39.0-py3-none-any.whl b/thirdparty/dist/fakeredis-2.39.0-py3-none-any.whl new file mode 100644 index 00000000..530236b4 Binary files /dev/null and b/thirdparty/dist/fakeredis-2.39.0-py3-none-any.whl differ diff --git a/thirdparty/dist/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl b/thirdparty/dist/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl deleted file mode 100644 index 48b691e8..00000000 Binary files a/thirdparty/dist/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl and /dev/null differ diff --git a/thirdparty/dist/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/thirdparty/dist/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index 0a25ca79..00000000 Binary files a/thirdparty/dist/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/thirdparty/dist/markupsafe-3.0.3.tar.gz b/thirdparty/dist/markupsafe-3.0.3.tar.gz deleted file mode 100644 index a8a7d8b7..00000000 Binary files a/thirdparty/dist/markupsafe-3.0.3.tar.gz and /dev/null differ diff --git a/thirdparty/dist/markupsafe-3.0.4-cp314-cp314-macosx_11_0_arm64.whl b/thirdparty/dist/markupsafe-3.0.4-cp314-cp314-macosx_11_0_arm64.whl new file mode 100644 index 00000000..1454e7f8 Binary files /dev/null and b/thirdparty/dist/markupsafe-3.0.4-cp314-cp314-macosx_11_0_arm64.whl differ diff --git a/thirdparty/dist/markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/thirdparty/dist/markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 00000000..1a47baed Binary files /dev/null and b/thirdparty/dist/markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/thirdparty/dist/model_bakery-1.24.1-py3-none-any.whl b/thirdparty/dist/model_bakery-1.24.1-py3-none-any.whl deleted file mode 100644 index 36656511..00000000 Binary files a/thirdparty/dist/model_bakery-1.24.1-py3-none-any.whl and /dev/null differ diff --git a/thirdparty/dist/model_bakery-1.24.2-py3-none-any.whl b/thirdparty/dist/model_bakery-1.24.2-py3-none-any.whl new file mode 100644 index 00000000..92130221 Binary files /dev/null and b/thirdparty/dist/model_bakery-1.24.2-py3-none-any.whl differ diff --git a/thirdparty/dist/msgspec-0.21.1-cp314-cp314-macosx_11_0_arm64.whl b/thirdparty/dist/msgspec-0.21.1-cp314-cp314-macosx_11_0_arm64.whl deleted file mode 100644 index 429bec8b..00000000 Binary files a/thirdparty/dist/msgspec-0.21.1-cp314-cp314-macosx_11_0_arm64.whl and /dev/null differ diff --git a/thirdparty/dist/msgspec-0.21.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/thirdparty/dist/msgspec-0.21.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index e583f350..00000000 Binary files a/thirdparty/dist/msgspec-0.21.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/thirdparty/dist/msgspec-0.22.0-cp314-cp314-macosx_11_0_arm64.whl b/thirdparty/dist/msgspec-0.22.0-cp314-cp314-macosx_11_0_arm64.whl new file mode 100644 index 00000000..837e9336 Binary files /dev/null and b/thirdparty/dist/msgspec-0.22.0-cp314-cp314-macosx_11_0_arm64.whl differ diff --git a/thirdparty/dist/msgspec-0.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/thirdparty/dist/msgspec-0.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 00000000..d68df727 Binary files /dev/null and b/thirdparty/dist/msgspec-0.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/thirdparty/dist/odfdo-3.26.3-py3-none-any.whl b/thirdparty/dist/odfdo-3.27.1-py3-none-any.whl similarity index 91% rename from thirdparty/dist/odfdo-3.26.3-py3-none-any.whl rename to thirdparty/dist/odfdo-3.27.1-py3-none-any.whl index dc3d6af0..1b57433f 100644 Binary files a/thirdparty/dist/odfdo-3.26.3-py3-none-any.whl and b/thirdparty/dist/odfdo-3.27.1-py3-none-any.whl differ diff --git a/thirdparty/dist/pydantic-2.13.5-py3-none-any.whl b/thirdparty/dist/pydantic-2.13.5-py3-none-any.whl deleted file mode 100644 index 45cb914d..00000000 Binary files a/thirdparty/dist/pydantic-2.13.5-py3-none-any.whl and /dev/null differ diff --git a/thirdparty/dist/pydantic-2.14.1-py3-none-any.whl b/thirdparty/dist/pydantic-2.14.1-py3-none-any.whl new file mode 100644 index 00000000..08a6c6d4 Binary files /dev/null and b/thirdparty/dist/pydantic-2.14.1-py3-none-any.whl differ diff --git a/thirdparty/dist/pydantic_core-2.46.5-cp314-cp314-macosx_11_0_arm64.whl b/thirdparty/dist/pydantic_core-2.46.5-cp314-cp314-macosx_11_0_arm64.whl deleted file mode 100644 index f4e511c2..00000000 Binary files a/thirdparty/dist/pydantic_core-2.46.5-cp314-cp314-macosx_11_0_arm64.whl and /dev/null differ diff --git a/thirdparty/dist/pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/thirdparty/dist/pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index 1f8d73f4..00000000 Binary files a/thirdparty/dist/pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/thirdparty/dist/pydantic_core-2.50.1-cp314-cp314-macosx_11_0_arm64.whl b/thirdparty/dist/pydantic_core-2.50.1-cp314-cp314-macosx_11_0_arm64.whl new file mode 100644 index 00000000..1526d374 Binary files /dev/null and b/thirdparty/dist/pydantic_core-2.50.1-cp314-cp314-macosx_11_0_arm64.whl differ diff --git a/thirdparty/dist/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/thirdparty/dist/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl new file mode 100644 index 00000000..d673a1e6 Binary files /dev/null and b/thirdparty/dist/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl differ diff --git a/thirdparty/dist/pytz-2026.4-py2.py3-none-any.whl b/thirdparty/dist/pytz-2026.5-py2.py3-none-any.whl similarity index 70% rename from thirdparty/dist/pytz-2026.4-py2.py3-none-any.whl rename to thirdparty/dist/pytz-2026.5-py2.py3-none-any.whl index 97f6ae21..ad5e16f6 100644 Binary files a/thirdparty/dist/pytz-2026.4-py2.py3-none-any.whl and b/thirdparty/dist/pytz-2026.5-py2.py3-none-any.whl differ diff --git a/uv.lock b/uv.lock index cb4e22ae..68f95b48 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 5 requires-python = "==3.14.*" resolution-markers = [ "sys_platform == 'linux'", @@ -95,11 +95,11 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.5.1" +version = "3.5.2" source = { registry = "thirdparty/dist" } wheels = [ - { path = "charset_normalizer-3.5.1-cp314-cp314-macosx_10_15_universal2.whl" }, - { path = "charset_normalizer-3.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, + { path = "charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl" }, + { path = "charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, ] [[package]] @@ -269,7 +269,7 @@ requires-dist = [ { name = "bleach", specifier = "==6.4.0" }, { name = "boolean-py", specifier = "==5.0" }, { name = "certifi", specifier = "==2026.7.22" }, - { name = "charset-normalizer", specifier = "==3.5.1" }, + { name = "charset-normalizer", specifier = "==3.5.2" }, { name = "clamd", specifier = "==1.0.2" }, { name = "click", specifier = "==8.5.0" }, { name = "confusable-homoglyphs", specifier = "==3.3.1" }, @@ -277,24 +277,24 @@ requires-dist = [ { name = "croniter", specifier = "==6.2.4" }, { name = "cyclonedx-python-lib", specifier = "==11.12.0" }, { name = "defusedxml", specifier = "==0.7.1" }, - { name = "django", specifier = "==6.1.1" }, + { name = "django", specifier = "==6.1.2" }, { name = "django-altcha", specifier = "==1.0.0" }, { name = "django-auth-ldap", specifier = "==5.3.0" }, { name = "django-axes", specifier = "==8.3.1" }, { name = "django-crispy-forms", specifier = "==2.7" }, { name = "django-debug-toolbar", specifier = "==8.0.0" }, { name = "django-environ", specifier = "==0.14.0" }, - { name = "django-filter", specifier = "==26.1" }, + { name = "django-filter", specifier = "==26.2" }, { name = "django-grappelli", specifier = "==5.0.0" }, { name = "django-guardian", specifier = "==3.5.0" }, { name = "django-notifications-patched", specifier = "==2.0.0" }, - { name = "django-otp", specifier = "==1.7.3" }, + { name = "django-otp", specifier = "==1.7.4" }, { name = "django-registration", specifier = "==5.2.1" }, { name = "django-rq", specifier = "==4.2.0" }, - { name = "djangorestframework", specifier = "==3.18.1" }, + { name = "djangorestframework", specifier = "==3.18.3" }, { name = "drf-yasg", specifier = "==1.21.15" }, { name = "et-xmlfile", specifier = "==2.0.0" }, - { name = "fakeredis", specifier = "==2.38.0" }, + { name = "fakeredis", specifier = "==2.39.0" }, { name = "gunicorn", specifier = "==26.2.0" }, { name = "idna", specifier = "==3.20" }, { name = "inflection", specifier = "==0.5.1" }, @@ -303,10 +303,10 @@ requires-dist = [ { name = "license-expression", specifier = "==30.4.4" }, { name = "lxml", specifier = "==6.1.3" }, { name = "markdown", specifier = "==3.11" }, - { name = "markupsafe", specifier = "==3.0.3" }, - { name = "model-bakery", specifier = "==1.24.1" }, - { name = "msgspec", specifier = "==0.21.1" }, - { name = "odfdo", specifier = "==3.26.3" }, + { name = "markupsafe", specifier = "==3.0.4" }, + { name = "model-bakery", specifier = "==1.24.2" }, + { name = "msgspec", specifier = "==0.22.0" }, + { name = "odfdo", specifier = "==3.27.1" }, { name = "openpyxl", specifier = "==3.1.5" }, { name = "packageurl-python", specifier = "==0.17.6" }, { name = "packaging", specifier = "==26.3" }, @@ -314,11 +314,11 @@ requires-dist = [ { name = "py-serializable", specifier = "==2.1.0" }, { name = "pyasn1", specifier = "==0.6.4" }, { name = "pyasn1-modules", specifier = "==0.4.2" }, - { name = "pydantic", specifier = "==2.13.5" }, - { name = "pydantic-core", specifier = "==2.46.5" }, + { name = "pydantic", specifier = "==2.14.1" }, + { name = "pydantic-core", specifier = "==2.50.1" }, { name = "python-dateutil", specifier = "==2.9.0.post0" }, { name = "python-ldap", specifier = "==3.4.8" }, - { name = "pytz", specifier = "==2026.4" }, + { name = "pytz", specifier = "==2026.5" }, { name = "pyyaml", specifier = "==6.0.3" }, { name = "qrcode", specifier = "==8.2" }, { name = "redis", specifier = "==8.1.0" }, @@ -343,14 +343,14 @@ provides-extras = ["dev"] [[package]] name = "django" -version = "6.1.1" +version = "6.1.2" source = { registry = "thirdparty/dist" } dependencies = [ { name = "asgiref" }, { name = "sqlparse" }, ] wheels = [ - { path = "django-6.1.1-py3-none-any.whl" }, + { path = "django-6.1.2-py3-none-any.whl" }, ] [[package]] @@ -422,13 +422,13 @@ wheels = [ [[package]] name = "django-filter" -version = "26.1" +version = "26.2" source = { registry = "thirdparty/dist" } dependencies = [ { name = "django" }, ] wheels = [ - { path = "django_filter-26.1-py3-none-any.whl" }, + { path = "django_filter-26.2-py3-none-any.whl" }, ] [[package]] @@ -463,13 +463,13 @@ sdist = { path = "django-notifications-patched-2.0.0.tar.gz" } [[package]] name = "django-otp" -version = "1.7.3" +version = "1.7.4" source = { registry = "thirdparty/dist" } dependencies = [ { name = "django" }, ] wheels = [ - { path = "django_otp-1.7.3-py3-none-any.whl" }, + { path = "django_otp-1.7.4-py3-none-any.whl" }, ] [[package]] @@ -499,13 +499,13 @@ wheels = [ [[package]] name = "djangorestframework" -version = "3.18.1" +version = "3.18.3" source = { registry = "thirdparty/dist" } dependencies = [ { name = "django" }, ] wheels = [ - { path = "djangorestframework-3.18.1-py3-none-any.whl" }, + { path = "djangorestframework-3.18.3-py3-none-any.whl" }, ] [[package]] @@ -535,14 +535,14 @@ wheels = [ [[package]] name = "fakeredis" -version = "2.38.0" +version = "2.39.0" source = { registry = "thirdparty/dist" } dependencies = [ { name = "redis" }, { name = "sortedcontainers" }, ] wheels = [ - { path = "fakeredis-2.38.0-py3-none-any.whl" }, + { path = "fakeredis-2.39.0-py3-none-any.whl" }, ] [[package]] @@ -621,44 +621,43 @@ wheels = [ [[package]] name = "markupsafe" -version = "3.0.3" +version = "3.0.4" source = { registry = "thirdparty/dist" } -sdist = { path = "markupsafe-3.0.3.tar.gz" } wheels = [ - { path = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl" }, - { path = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, + { path = "markupsafe-3.0.4-cp314-cp314-macosx_11_0_arm64.whl" }, + { path = "markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, ] [[package]] name = "model-bakery" -version = "1.24.1" +version = "1.24.2" source = { registry = "thirdparty/dist" } dependencies = [ { name = "django" }, ] wheels = [ - { path = "model_bakery-1.24.1-py3-none-any.whl" }, + { path = "model_bakery-1.24.2-py3-none-any.whl" }, ] [[package]] name = "msgspec" -version = "0.21.1" +version = "0.22.0" source = { registry = "thirdparty/dist" } wheels = [ - { path = "msgspec-0.21.1-cp314-cp314-macosx_11_0_arm64.whl" }, - { path = "msgspec-0.21.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, + { path = "msgspec-0.22.0-cp314-cp314-macosx_11_0_arm64.whl" }, + { path = "msgspec-0.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, ] [[package]] name = "odfdo" -version = "3.26.3" +version = "3.27.1" source = { registry = "thirdparty/dist" } dependencies = [ { name = "lxml" }, { name = "typing-extensions" }, ] wheels = [ - { path = "odfdo-3.26.3-py3-none-any.whl" }, + { path = "odfdo-3.27.1-py3-none-any.whl" }, ] [[package]] @@ -728,7 +727,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.13.5" +version = "2.14.1" source = { registry = "thirdparty/dist" } dependencies = [ { name = "annotated-types" }, @@ -737,19 +736,19 @@ dependencies = [ { name = "typing-inspection" }, ] wheels = [ - { path = "pydantic-2.13.5-py3-none-any.whl" }, + { path = "pydantic-2.14.1-py3-none-any.whl" }, ] [[package]] name = "pydantic-core" -version = "2.46.5" +version = "2.50.1" source = { registry = "thirdparty/dist" } dependencies = [ { name = "typing-extensions" }, ] wheels = [ - { path = "pydantic_core-2.46.5-cp314-cp314-macosx_11_0_arm64.whl" }, - { path = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, + { path = "pydantic_core-2.50.1-cp314-cp314-macosx_11_0_arm64.whl" }, + { path = "pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, ] [[package]] @@ -775,10 +774,10 @@ sdist = { path = "python_ldap-3.4.8.tar.gz" } [[package]] name = "pytz" -version = "2026.4" +version = "2026.5" source = { registry = "thirdparty/dist" } wheels = [ - { path = "pytz-2026.4-py2.py3-none-any.whl" }, + { path = "pytz-2026.5-py2.py3-none-any.whl" }, ] [[package]]