diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d55b1752c..544d71fedb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python-version: ['3.10', '3.13'] + python-version: ['3.10', '3.14'] db-backend: [mysql, postgres] steps: - uses: actions/checkout@v6 @@ -94,7 +94,7 @@ jobs: - name: Run package status tests first run: | pytest rdmo/core/tests/test_package_status.py --nomigrations --verbose - if: matrix.python-version == '3.13' && matrix.db-backend == 'postgres' + if: matrix.python-version == '3.14' && matrix.db-backend == 'postgres' - name: Run Tests run: | pytest -p randomly -p no:cacheprovider --cov --reuse-db --numprocesses=auto --dist=loadscope @@ -114,7 +114,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python-version: ['3.13'] + python-version: ['3.14'] db-backend: [postgres] steps: - uses: actions/checkout@v6 @@ -184,7 +184,7 @@ jobs: persist-credentials: false - uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.14" cache: pip - run: python -Im pip install --editable .[dev] - run: python -Ic 'import rdmo; print(rdmo.__version__)' @@ -199,7 +199,7 @@ jobs: persist-credentials: false - uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.14" cache: pip - name: Download wheel uses: actions/download-artifact@v6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 170b542dd5..3b51214069 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog 📔 +## [RDMO 2.5.0](https://github.com/rdmorganiser/rdmo/releases/tag/2.5.0) + +**Milestone**: [2.5.0](https://github.com/rdmorganiser/rdmo/milestone/26) + +**Commit history**: [2.4.0...2.5.0](https://github.com/rdmorganiser/rdmo/compare/2.4.0...2.5.0) + + ## [RDMO 2.4.0](https://github.com/rdmorganiser/rdmo/releases/tag/2.4.0) (December 15, 2025) ### Main improvements ⭐ diff --git a/pyproject.toml b/pyproject.toml index 92ab2654e5..be816f08ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ requires-python = ">=3.10" classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", - "Framework :: Django :: 4.2", + "Framework :: Django :: 5.2", "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python", @@ -31,6 +31,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] dynamic = [ "version", @@ -41,7 +42,7 @@ dependencies = [ # in minor version updates anytime "defusedcsv>=2.0,<4.0", "defusedxml>=0.7.1,<1.0", - "django>=4.2,<5.0", + "django>=5.2.8,<6.0", "django-cleanup>=8.0,<10.0", "django-compressor>=4.4,<5.0", "django-extensions>=3.2,<5.0", @@ -79,7 +80,7 @@ allauth = [ dev = [ "pipdeptree>=2.13,<3.0", "pre-commit>=3.4,<5.0", - "setuptools>=73,<81", + "setuptools>=73,<83", ] gunicorn = [ "gunicorn>=23.0,<24.0", @@ -203,15 +204,11 @@ markers = [ "e2e: marks tests as end-to-end tests using playwright (deselect with '-m \"not e2e\"')", ] filterwarnings = [ - # fail on RemovedInDjango50Warning exception - "error::django.utils.deprecation.RemovedInDjango50Warning", + # throw an error when using methods deprecated in the next django version + "error::django.utils.deprecation.RemovedInNextVersionWarning", # ignore warnings raised by widget_tweaks.py "ignore:'maxsplit' is passed as positional argument", - - # ignore warnings raised from within django itself - # django/core/files/storage/__init__.py - "ignore:django.core.files.storage.get_storage_class is deprecated:django.utils.deprecation.RemovedInDjango51Warning", ] [tool.coverage.run] diff --git a/rdmo/core/settings.py b/rdmo/core/settings.py index 237846cef6..2531e8c4b4 100644 --- a/rdmo/core/settings.py +++ b/rdmo/core/settings.py @@ -75,6 +75,8 @@ }, ] +MESSAGE_STORAGE = "django.contrib.messages.storage.session.SessionStorage" + COMPRESS_PRECOMPILERS = ( ('text/x-scss', 'django_libsass.SassCompiler'), ) diff --git a/rdmo/core/tests/test_utils.py b/rdmo/core/tests/test_utils.py index 2c446d5192..eae862cbe7 100644 --- a/rdmo/core/tests/test_utils.py +++ b/rdmo/core/tests/test_utils.py @@ -42,7 +42,11 @@ ] invalid_date_strings = [ - ("2025-02-31","day is out of range for month"), + ("2025-02-31", ( + "day is out of range for month", # Python 3.10 + "day 31 must be in range 1..28 for month 2 in year 2025" # Python 3.14 + ) + ), ("2025-17-02", "month must be in 1..12"), ("99/99/9999", "Invalid date format"), ("abcd-ef-gh", "Invalid date format"), @@ -91,11 +95,14 @@ def test_parse_date_from_string_valid_formats(settings, locale, date_string, exp @pytest.mark.parametrize("invalid_date, error_msg", invalid_date_strings) def test_parse_date_from_string_invalid_formats(settings, invalid_date, error_msg): - if not isinstance(invalid_date,str): - with pytest.raises(TypeError, match=error_msg): + patterns = error_msg if isinstance(error_msg, (tuple, list)) else (error_msg,) + match = "|".join(f"(?:{pattern})" for pattern in patterns) + + if not isinstance(invalid_date, str): + with pytest.raises(TypeError, match=match): parse_date_from_string(invalid_date) else: - with pytest.raises(ValueError,match=error_msg): + with pytest.raises(ValueError, match=match): parse_date_from_string(invalid_date) diff --git a/rdmo/views/templates/views/tags/value.html b/rdmo/views/templates/views/tags/value.html index 0e307fa2bd..61f4826ffe 100644 --- a/rdmo/views/templates/views/tags/value.html +++ b/rdmo/views/templates/views/tags/value.html @@ -1,5 +1 @@ -{% if value.file_url %} -{% include 'views/tags/value_file.html' %} -{% else %} -{{ value.value_and_unit }} -{% endif %} +{% if value.file_url %}{% include 'views/tags/value_file.html' %}{% else %}{{ value.value_and_unit }}{% endif %} \ No newline at end of file diff --git a/rdmo/views/templates/views/tags/value_inline_list.html b/rdmo/views/templates/views/tags/value_inline_list.html index b446d846c4..b7ee8b014f 100644 --- a/rdmo/views/templates/views/tags/value_inline_list.html +++ b/rdmo/views/templates/views/tags/value_inline_list.html @@ -1,3 +1 @@ -{% for value in values %} - {{ value.value_and_unit }}{% if not forloop.last %}; {% endif %} -{% endfor %} +{% for value in values %}{{ value.value_and_unit }}{% if not forloop.last %}; {% endif %}{% endfor %} \ No newline at end of file diff --git a/testing/config/settings/base.py b/testing/config/settings/base.py index 23cd12fa07..d53b5f583f 100644 --- a/testing/config/settings/base.py +++ b/testing/config/settings/base.py @@ -1,4 +1,5 @@ import os +from warnings import filterwarnings from django.utils.translation import gettext_lazy as _ @@ -110,3 +111,13 @@ PROJECT_CONTACT = True PROJECT_CONTACT_RECIPIENTS = ['email@example.com'] + +# Ref: https://adamj.eu/tech/2023/12/07/django-fix-urlfield-assume-scheme-warnings +filterwarnings( + "ignore", "The FORMS_URLFIELD_ASSUME_HTTPS transitional setting is deprecated." +) +# This value will change from False to True in Django 6.0 +# Refs: +# - https://docs.djangoproject.com/en/5.2/ref/settings/#forms-urlfield-assume-https +# - https://docs.djangoproject.com/en/5.2/ref/forms/fields/#django.forms.URLField.assume_scheme +FORMS_URLFIELD_ASSUME_HTTPS = True diff --git a/testing/export/project.html b/testing/export/project.html index 956c01e3ce..2094cb854e 100644 --- a/testing/export/project.html +++ b/testing/export/project.html @@ -8,34 +8,34 @@

Single questions

Text

Text?

-Lorem ipsum dolor sit amet + Lorem ipsum dolor sit amet

Textarea

Textarea?

-Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet.

Yes or no

Yes or no?

-Yes + Yes

Radio buttons

Radio buttons?

-Text: Lorem ipsum + Text: Lorem ipsum

Select drop-down

Select drop-down?

-One + One

Select drop-down (free)

Select drop-down (free)?

Range slider

Range slider?

-37 + 37

File

File?

@@ -45,66 +45,66 @@

File

Datetime

Date picker?

-Jan. 1, 2018 + Jan. 1, 2018

Collections

Text

Text?

Textarea

Textarea?

Yes or no

Yes or no?

Radio buttons

Radio buttons?

Select drop-down

Select drop-down?

Select drop-down (free)

@@ -113,26 +113,26 @@

Range slider

Range slider?

Date picker

Date picker?

File

@@ -149,42 +149,42 @@

Checkbox

Checkbox?

Sets

Individual sets I

Text?

-Lorem ipsum dolor sit amet + Lorem ipsum dolor sit amet

Textarea?

-Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet.

Yes or no?

-Yes + Yes

Radio buttons?

-Text: Lorem ipsum + Text: Lorem ipsum

Select drop-down?

-One + One

Select drop-down (free)?

Range slider?

-37 + 37

Date picker?

-Jan. 1, 2018 + Jan. 1, 2018

File?

@@ -194,80 +194,80 @@

Individual sets II

Text?

Textarea?

Yes or no?

Radio buttons?

Select drop-down?

Select drop-down (free)?

Range slider?

Date picker?

File?

@@ -282,96 +282,96 @@

Individual sets II

Checkbox?

Set collections I

Text?

Set "First":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr + Lorem ipsum dolor sit amet, consetetur sadipscing elitr

Set "Second":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr + Lorem ipsum dolor sit amet, consetetur sadipscing elitr

Textarea?

Set "First":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet.

Set "Second":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet.

Yes or no?

Set "First":  -Yes + Yes

Set "Second":  -No + No

Radio buttons?

Set "First":  -One + One

Set "Second":  -Two + Two

Select drop-down?

Set "First":  -One + One

Set "Second":  -Two + Two

Select drop-down (free)?

Range slider?

Set "First":  -1 + 1

Set "Second":  -2 + 2

Date picker?

Set "First":  -Jan. 7, 2018 + Jan. 7, 2018

Set "Second":  -Feb. 7, 2018 + Feb. 7, 2018

File?

Set collections II

Text?

Set "First":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr + Lorem ipsum dolor sit amet, consetetur sadipscing elitr

Set "Second":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr + Lorem ipsum dolor sit amet, consetetur sadipscing elitr

Textarea?

Set "First":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet.

Set "Second":  -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est. Lorem ipsum dolor sit amet.

Yes or no?

@@ -379,13 +379,13 @@

Set collections II

@@ -393,13 +393,13 @@

Set collections II

Radio buttons?

@@ -408,13 +408,13 @@

Set collections II

@@ -422,13 +422,13 @@

Set collections II

Select drop-down?

@@ -437,15 +437,15 @@

Set collections II

Set "Second":  -Three + Three

Select drop-down (free)?

Range slider?

@@ -454,15 +454,15 @@

Set collections II

Set "Second":  -86 + 86

Date picker?

@@ -470,10 +470,10 @@

Set collections II

@@ -481,10 +481,10 @@

Set collections II

File?

@@ -494,37 +494,37 @@

Set collections II

Set "Second":  -One + One

Conditions

Input

Text

-test + test

Option

-One + One

Text I

text_contains?

-test + test

Text II

text empty?

Text III

text_equal?

-test + test

Text IV

text_greater_than?

@@ -537,7 +537,7 @@

Text VII

Text VIII

text_not_empty?

-test + test

Text IX

text_not_equal?

@@ -546,12 +546,12 @@

Options I

Options II

option_equal?

-One + One

Options III

option_not_empty?

-One + One

Options IV

option_not_equal?

@@ -594,20 +594,20 @@

A set of questionsets and questions

A?

Set "First", Block #1:  -a0 + a0

Set "First", Block #2:  -a1 + a1

B?

Set "First", Block #1:  -b1 + b1

Set "First", Block #2:  -b1 + b1

C?

@@ -615,10 +615,10 @@

A set of questionsets and questions

@@ -626,40 +626,40 @@

A set of questionsets and questions

Y?

Set "First", Block #1, Set #1:  -Three + Three

Set "First", Block #2, Set #1:  -Three + Three

Set "Second", Block #1, Set #1:  -Three + Three

Set "Second", Block #2, Set #1:  -Three + Three

Set "Second", Block #3, Set #1:  -One + One

Set "Second", Block #3, Set #2:  -Two + Two

Set "Second", Block #3, Set #3:  -Three + Three

Question

Block with optional questions