Upgrade to django 5.2 - #5497
Draft
yakky wants to merge 28 commits into
Draft
Conversation
utils/management/commands/backup.py had zero dedicated test coverage (its only prior 'backup' hit in the test suite was an unrelated code comment). This is Phase 1 item openlibhums#1 of the Django 5.2 migration plan: a regression oracle for the boto (v2) -> boto3 migration, run and confirmed green against the current boto 2.46.1 dependency. Adds BackupCommandS3Test, covering: - the S3 connection is opened with the configured region/host/credentials and bucket, without making a real network call (boto.s3.connect_to_region and the boto.s3.key.Key class are mocked) - a completion email is sent to superuser accounts when BACKUP_TYPE=s3 and BACKUP_EMAIL=True - an error email is sent (and the command does not raise) when the S3 connection fails The command's internal call_command('dumpdata', ...) step is faked out: under this repo's sqlite test settings, a real dumpdata run fails with 'no such table: core_pgfiletext' because core.models.PGFileText declares required_db_vendor='postgresql' and has no table on sqlite, yet dumpdata still tries to serialize it. That is a pre-existing sqlite/postgres model incompatibility unrelated to the S3 path under test here, so it is faked out rather than worked around. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
review/logic.py:serve_review_file() builds a .docx review form with python-docx and had zero test coverage. This is Phase 1 item openlibhums#2 of the Django 5.2 migration plan: a regression oracle for the python-docx 0.8.11 -> 1.2.0 upgrade, run and confirmed green against the current python-docx 0.8.11 dependency. Adds ServeReviewFileTests.test_serve_review_file_produces_valid_docx, which builds a real ReviewAssignment with a ReviewForm carrying two ReviewFormElements, calls serve_review_file(), reads the generated docx bytes back out of the StreamingHttpResponse, and asserts: - the document's first heading is 'Review #<pk>' - a heading contains the article title - each ReviewFormElement's name appears as a level-2 heading Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Re-applied by hand after rebasing this branch onto the correct r-v1.9.x base: the original commit targeted utils/tests/__init__.py because the branch had been accidentally built on top of origin/master, where utils/tests.py had not yet been split into a package the same way r-v1.9.x already has (r-v1.9.x keeps the real content in test_utils.py, with an empty __init__.py). Ported the two new test methods and their imports (retrieve_tokens, HTTPError) into the existing TestORCiDRecord class in test_utils.py instead.
Removes packages verified via git grep to have zero real usage in src/, per the Phase 2 migration plan's Verified unused packages page: - ipaddress: Python 2 stdlib backport, zero imports - kitchen: zero imports - python-wordpress-xmlrpc (dev-requirements.txt): zero imports repo-wide - bs4: redundant meta-package; beautifulsoup4 already provides the same 'bs4' importable namespace used across 27 files - six: only needed transitively via ebooklib's own install_requires, zero direct imports in src/ - pycparser: only needed transitively via cffi, zero direct imports - ua-parser: only needed transitively via user-agents, zero direct imports (user-agents itself is still a direct dependency, kept) - django-dynamicsites (openlibhums git-installed fork): zero imports, no INSTALLED_APPS/MIDDLEWARE entry; also already broken under today's Django 4.2 (render_to_response(context_instance=...) and django.utils.http.urlquote were both removed years ago). Also removes its now-stale entry from pyproject.toml's ruff exclude list. Full test suite re-run after removal: 1295 tests, all pass, no change from baseline. Part of Phase 2 of the Django 5.2 migration plan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mechanical import-source swap only, no behavior change: - 'import mock' -> 'from unittest import mock' - 'from mock import X' -> 'from unittest.mock import X' Touches the 13 files found via git grep for '^import mock|from mock import' (src/api/tests/test_preprints.py, src/core/tests/test_app.py, src/core/tests/test_logic.py, src/core/tests/test_views.py, src/cron/management/commands/send_publication_notifications.py, src/identifiers/tests/test_logic.py, src/repository/tests/test_models.py, src/security/test_security.py, src/submission/tests/test_logic.py, src/submission/tests/test_workflow.py, src/typesetting/tests.py, src/utils/management/commands/test_fire_event.py, src/utils/tests/test_utils.py). test_app.py had both 'from mock import patch' and a separate 'import mock' for mock.patch(...) usage elsewhere in the file; both were swapped to their unittest.mock equivalents. Removes the now-unused 'mock' pin from requirements.txt. Full test suite re-run: 1295 tests, all pass, no change from baseline. Part of Phase 2 of the Django 5.2 migration plan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the abandoned boto v2 SDK with boto3 in
utils/management/commands/backup.py's S3 upload path, guarded by
Phase 1's utils/tests/test_backup.py.
Implementation decisions:
- boto.s3.connect_to_region(END_POINT, ..., host=S3_HOST) + Key +
set_contents_from_file(cb=..., num_cb=200) becomes
boto3.client("s3", region_name=..., endpoint_url=..., ...) +
upload_fileobj(..., Callback=...).
- END_POINT vs S3_HOST: per janeway_global_settings.py's documented
defaults (END_POINT = "eu-west-2" # eg. eu-west-1, S3_HOST =
"s3.eu-west-2.amazonaws.com" # eg. s3.eu-west-1.amazonaws.com),
END_POINT is a plain AWS region name and S3_HOST is that region's
standard S3 endpoint hostname - not evidence of a non-AWS/custom
S3-compatible endpoint. boto3.client() is therefore called with
region_name=END_POINT (which boto3 needs to resolve/sign requests)
*and* endpoint_url=f"https://{S3_HOST}" so a deployment that has
customised S3_HOST to point somewhere else keeps behaving exactly as
it did under boto2's host= override, rather than silently starting
to ignore that setting.
- mycb()'s signature changes from cb(so_far, total) to
Callback(bytes_transferred), since boto3's upload_fileobj only ever
passes the callback the number of bytes transferred in that
invocation (no running total or file size, unlike boto2). Rather
than reconstructing a running total via a closure, the callback just
reports the chunk size transferred and drops the "out of {total}"
part of the printed message - simplest option that preserves visible
upload progress without adding statefulness only used for a log
line.
- requirements.txt: boto==2.46.1 -> boto3==1.43.75 (latest at time of
writing).
test_backup.py's mocks were updated to target the new call sites
(boto3.client instead of boto.s3.connect_to_region/Key) while keeping
its behavioural assertions unchanged: bucket name, key naming under
'backups/...', and email-on-success/failure. The test's existing
_fake_dumpdata() workaround for the pre-existing sqlite/PGFileText
dumpdata incompatibility (flagged in the Phase 1 report as a decision
for whoever does this migration) is left as-is and not addressed here
- it is a separate, pre-existing production bug unrelated to the
boto3 swap, out of scope for this task.
utils.tests.test_backup run in isolation: 2/2 pass. Full suite:
1295 tests, all pass, no change from baseline.
Part of Phase 2 of the Django 5.2 migration plan.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…atch 1) - django-hijack 3.2.1 -> 3.7.8 - django-recaptcha 3.0.0 -> 4.1.0 - django-simple-history 3.10.1 -> 3.12.0 (not 3.13.0: that release requires django>=5.2, dropping 4.2 support; 3.12.0 is the latest release still compatible with the Django 4.2.29 pin this phase keeps) - django-tinymce 3.7.1 -> 5.0.0 - mozilla-django-oidc 4.0.1 -> 5.0.2 - django-bootstrap4 23.2 -> 26.1 django-recaptcha 4.x renamed its top-level package/app from `captcha` to `django_recaptcha` (documented in the project's own README/install instructions as of the 4.0.0 release). Updated the one INSTALLED_APPS entry and the two field/widget imports in utils/forms.py accordingly. beautifulsoup4 was transitively bumped 4.9.3 -> 4.15.0 by django-bootstrap4's `beautifulsoup4>=4.10.0` floor; this is also the target version for the Batch 2 utility-package bump, so left as-is. Full suite: 1295 tests, all pass.
…ing (batch 2) - beautifulsoup4 4.9.3 -> 4.15.0 (already transitively pulled in by batch 1's django-bootstrap4 bump; pin updated to match) - colorlog 3.1.4 -> 6.12.0 - chardet 3.0.4 -> 7.6.0 - crossrefapi 1.5.0 -> 1.7.0 - freezegun 1.2.0 -> 1.5.5 - html2text 2017.10.4 -> 2025.4.15 - iso639-lang 2.6 -> 2.6.3 - more-itertools 10.1.0 -> 11.1.0 Batch 6 (urllib3<2 pin removal) folded in here rather than done as its own later step: crossrefapi 1.7.0 hard-requires urllib3>=2.2.3, so resolving this batch at all forces the ceiling's removal - it's no longer a "try and see" experiment, it's a direct conflict. This is also the strongest possible confirmation of the dependency analysis's suspicion that the pin (originally added for openlibhums#3736, a requests/boto2-era urllib3 2.0 incompatibility) is obsolete now that Phase 2 moved us to boto3 and requests is pinned to 2.32.4, which fully supports urllib3 2.x. pip resolved urllib3 to 2.7.0 with the ceiling removed. Full suite: 1295 tests, all pass.
…x (batch 3) - lxml 6.0.0 -> 6.1.2 - markdown: was unpinned -> pinned ==3.10.3 - packaging 23.2 -> 26.3 - pdfminer.six: was unpinned -> pinned ==20260107 - psycopg2-binary 2.9.10 -> 2.9.12 - pyasn1 0.1.9 -> 0.6.4 (no direct call site in Janeway code; pure transitive dependency of the crypto/OIDC stack) - PyJWT 2.4.0 -> 2.13.0 - Pillow 10.2.0 -> 12.3.0 pdfkit left untouched (permanently out of scope this migration). Full suite: 1295 tests, all pass.
- python-dateutil 2.8.1 -> 2.9.0.post0 - python-crontab 2.2.3 -> 3.3.0 (major bump; confirmed real call site in cron/management/commands/install_cron.py - manually exercised with `manage.py install_cron --action=test` post-bump, which constructs CronTab(user=True), iterates jobs, calls tab.new(), cron_job.setall(), minute.every(), and tab.render() without writing to the real crontab; output was correct and unchanged in shape) - requests 2.32.4 -> 2.34.2 - sqlparse 0.4.4 -> 0.6.0 - tqdm 4.66.3 -> 4.70.0 - docutils 0.21.2 -> 0.23 Full suite: 1295 tests, all pass.
- coverage: unpinned -> ==7.15.4 - ipdb: unpinned -> ==0.13.13 - marshmallow: unpinned -> ==4.3.1 (no direct call site in Janeway code; dev/tooling-only transitive dependency) - freezegun: unpinned -> ==1.5.5 (matches the requirements.txt pin from batch 2, so both files now agree) - snakeviz: unpinned -> ==2.2.2 (referenced only in a docstring in utils/management/base.py as an external profiling tool a developer runs manually; no import in Janeway code) - django-browser-reload: was unpinned -> ==1.21.0 - tox: unpinned -> ==4.60.0 - ruff: was `>=0.15` -> ==0.16.4 Hygiene fix: pyproject.toml's `dev` extra pinned bare `ruff` while dev-requirements.txt pinned `ruff>=0.15` - the two could silently diverge. Made dev-requirements.txt the source of truth (it's what CI and `make` targets actually install from) and pinned pyproject.toml's `dev` extra to the exact same `ruff==0.16.4`. Verified `ruff format --check .` against the new ruff version: 1252 files already formatted, no drift. Full suite: 1295 tests, all pass.
Confirmed real call site: review/logic.py:serve_review_file() builds a .docx review form via Document(), add_heading(text, 0/1/2), add_paragraph(), add_table()/add_row()/.cells. Gated by the Phase 1 regression test review/tests/test_logic.py (ServeReviewFileTests.test_serve_review_file_produces_valid_docx), added specifically ahead of this upgrade. Checked python-docx 1.2.0's add_heading() source directly: the level-0-heading style is still "Title" in both 0.8.11 and 1.2.0 (not "Heading 0" as flagged as a possible risk) - add_heading, add_table, add_paragraph and save() all have unchanged signatures across the 1.0.0 boundary (type hints added only). No code change needed in serve_review_file(). Verification: - review.tests.test_logic passed against python-docx 0.8.11 (baseline) - bumped to 1.2.0 - review.tests.test_logic passed again unchanged - full suite: 1295 tests, all pass
Searched Janeway's own code thoroughly for django_countries usage (CountryField, `import django_countries`, INSTALLED_APPS entry, templates, plugins) and found none - it is not even in INSTALLED_APPS. The `Country` model referenced in core/models.py and core/logic.py is Janeway's own local model, unrelated to this package. This is a genuinely zero-call-site dependency in the current codebase (per the governing rule, full-suite-green is sufficient evidence for such packages). Confirmed the `[pyuca]` extra still resolves in 9.0.0 (provides_extra: ['pyuca'], requires_dist includes 'pyuca; extra == "pyuca"'). requires_python is now >=3.10, compatible with this phase's Python 3.11 venv. Full suite: 1295 tests, all pass.
- maxminddb 2.5.1 -> 3.1.1 - geoip2 4.8.0 -> 5.3.0 - Faker 17.6.0 -> 40.36.0 Confirmed real call sites: - metrics/logic.py:get_iso_country_code() uses geoip2.database.Reader against the bundled GeoLite2-Country.mmdb, called from store_article_access() on every article view. This is already exercised end-to-end (not just imported) by the existing metrics/tests.py::ArticleAccessTests, which hit real article URLs and assert on the resulting ArticleAccess rows. Ran this test module before (geoip2 4.8.0/maxminddb 2.5.1: 4 passed) and after (geoip2 5.3.0/maxminddb 3.1.1: 4 passed, unchanged) the bump. - repository/management/commands/generate_preprints.py and utils/management/commands/create_fake_news_items.py both use `Faker()` with fake.sentence(), fake.text(), fake.first_name(), fake.last_name(), fake.word(), fake.date() - all long-stable core providers, no Faker.seed() call anywhere in Janeway's code. Coverage gap (flagged, not fixed here): neither generate_preprints nor create_fake_news_items has any existing automated test - grepped the whole tree, found none. Since the Faker jump is 17.6.0 -> 40.36.0 (23 majors), verified by direct interpreter smoke-test that fake.sentence()/.text()/.first_name()/.last_name()/.word()/.date() all still work correctly under 40.36.0, but this is not a substitute for real command-level test coverage. Recommend the orchestrating session consider a dedicated test for at least one of these two commands as a follow-up. geoip2 5.3.0 pulled in aiohttp (already present via another dependency, bumped 3.13.5 -> 3.14.3) for its new async client support; not used by Janeway's synchronous call site. Full suite: 1295 tests, all pass.
Installed django-upgrade==1.32.0 (current latest stable on PyPI) as a
dev-only dependency and ran it once against all of Janeway's own source
(git ls-files 'src/**/*.py', excluding plugins/third-party code) with
--target-version 5.2. Django itself stays pinned at 4.2.29; this is a
purely mechanical, backward-compatible syntax rewrite (Phase 4 of the
Django 5.2 migration plan). Followed by `ruff format .`.
Fixers that actually fired (45 source files touched, 0 migrations in
the final diff):
- django_urls (min_version 2.0): rewrote `re_path()` calls using simple,
unambiguous regex groups (\d+ -> <int:...>, etc.) to `path()` with
converters, across ~30 urls.py files (core/include_urls.py,
journal/urls.py, repository/urls.py, review/urls.py, typesetting/urls.py,
submission/urls.py, production/urls.py, proofing/urls.py, cms/urls.py,
copyediting/urls.py, and many smaller ones). Calls with complex regex
(alternation, char classes, `.*`, etc.) were correctly left as re_path().
- test_http_headers: rewrote HTTP_USER_AGENT=/HTTP_REFERER= kwargs on
django.test.Client calls to headers={...} dicts, in
core/tests/test_app.py (x2), core/tests/test_views.py (x1),
metrics/tests.py (x4). journal/tests/test_middleware.py was NOT
touched even though it has HTTP_ACCEPT_LANGUAGE kwargs, because those
calls go through RequestFactory rather than the test Client, which
this fixer does not target.
- request_headers (META["HTTP_*"] -> headers[...]): core/files.py (x2),
core/logic.py, core/views.py, metrics/logic.py, proofing/views.py,
repository/logic.py, submission/models.py, typesetting/views.py (x3).
- admin_action (short_description attr -> @admin.action(description=)):
metrics/admin.py (x2).
- timezone_utc (django.utils.timezone.utc -> datetime.timezone.utc):
api/oai/base.py.
- default_app_config removal: core/__init__.py.
Fixers that did NOT fire despite being expected from the prior phases'
dependency analysis:
- model_field_choices (choices=Enum.choices -> choices=Enum): 0 hits.
core/models.py (RORStatus), journal/models.py (PublishingStatus), and
utils/models.py (RORImportStatus) all define their TextChoices enum as
a nested class inside the model class itself. django-upgrade's fixer
only scans top-level ast.ClassDef nodes in the module body for
Django-choices-type base classes, so it never sees these nested
definitions. This is a real detection-limitation of the tool, not a
bug we should hand-patch here.
- format_html: 0 hits. All existing format_html() calls in
repository/models.py and core/models.py already use the correct
argument form (format_html("...{}", value)); none used the
.format()-then-pass-string anti-pattern this fixer targets.
- index_together, settings_storages, assert_set_methods,
postgres_aggregate_order_by, staticfiles_find_all: confirmed still
zero usage.
Escalation per Phase 3's rule - reverted, not applied:
- check_constraint_condition (CheckConstraint(check=...) ->
CheckConstraint(condition=...)) fired in cms/models.py,
core/model_utils.py (the check_exclusive_fields_constraint() helper),
and 3 migration files (cms/migrations/0022, core/migrations/0104,
submission/migrations/0085). Applying it broke `manage.py check` and
the test suite outright: Django 4.2.29's CheckConstraint.__init__
only accepts `check=`, not `condition=` - `condition` was only added
in Django 5.1. The plan's assumption that all target-5.2 rewrites are
backward-compatible with 4.2 does not hold for this one fixer. All 5
files were reverted to `check=` for this phase; the rewrite to
`condition=` is correct and should be reapplied once Django is
actually bumped to >=5.1 (Phase 5+). No other changes in those 5
files were reverted - only the check=/condition= keyword.
Verification:
- Baseline before rewrite: 1295 tests, all pass, 123.1s (matches
Phase 3's final state).
- `manage.py check`: clean after the constraint revert (it errored with
"unexpected keyword argument 'condition'" before the revert).
- `ruff format --check .`: clean.
- Full suite after rewrite + revert + reformat: 1295 tests, all pass,
120.9s - identical pass count to baseline.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Surfaced via python -W error on Django's RemovedInDjango50/51Warning classes (applied programmatically, since -W/PYTHONWARNINGS command-line parsing of dotted category paths fails before site-packages are on the import path): - utils/testing/helpers.py: create_journal_with_test_status() set journal.name (a SettingValue-backed property) before journal.save(), passing an unsaved Journal instance into a related filter (SettingValue.objects.get_or_create(journal=journal)). Under Django 4.2 this silently matched journal_id IS NULL rows instead of the intended journal; Django 5.0+ raises ValueError. Reordered to save() before setting .name. - core/tests/test_views.py: replaced the deprecated django.utils.timezone.utc alias with datetime.timezone.utc. Not touched (not deprecated-API usage in Janeway's own code, both confirmed as expected/non-actionable): - test_affiliation_get_or_create_without_ror_value_error deliberately exercises the future ValueError path; it only appears as a failure here because forcing the warning to error mode pre-empts the ValueError it's designed to catch. - The forms "default.html" template RemovedInDjango50Warning (4 tests) reflects a Django 5.0 default-behavior change, not a deprecated call site in Janeway's code; resolves itself once Django is bumped.
Empirically staged per the migration plan: bumped only Django first, keeping djangorestframework==3.15.2, django-debug-toolbar==5.1.0 and django-modeltranslation==0.18.11 pinned at their old versions, to isolate what actually breaks from Django itself vs. the three version-gated packages. Result: none of the three gated packages broke at their old pin against Django 5.2.17 for any code path the test suite exercises. Every failure below traces to Janeway's own code: - utils/function_cache.py: mutable_cached_property.setter() called cached_property.__init__(self.func, self.name), but Django 5.0 removed the deprecated 'name' argument (RemovedInDjango50Warning in 4.2, hard TypeError in 5.x) since __set_name__ makes it redundant. Dropped the argument. - core/model_utils.py: DynamicChoiceField.formfield() called form_element.choices.append(choice); Django 5.x's ChoiceField.choices is normalized through a getter/setter pair (BlankChoiceIterator on read) and is no longer a plain mutable list. Reassign via the choices setter instead. - submission/admin.py, repository/admin.py: Django 5.x's admin system checks now enforce admin.E013 for filter_horizontal/filter_vertical entries naming a ManyToManyField with a custom 'through' model. ArticleAdmin and PreprintAdmin both listed 'keywords' (through KeywordArticle/KeywordPreprint) in filter_horizontal, redundantly duplicating the dedicated KeywordArticleInline/KeywordPreprintInline already present in the same admin classes. Removed the redundant, now-invalid filter_horizontal entries. - core/models.py: File.index_full_text() called FileTextModel.objects.create(contents=..., file=self). 'file' is the reverse accessor for File.text (a OneToOneField), not a real field on FileText; Django 5.x's QuerySet.create() now explicitly rejects reverse-one-to-one kwargs (they were always a silent no-op in 4.2 - the relation is actually established by the very next line, self.text = file_text_obj). Dropped the ineffective kwarg. Full suite: 1295/1295 tests considered, only 3 pre-existing failures in comms.tests.NewsItemOrderingTest, all traced to an environment clock artifact unrelated to Django (the sandbox's local wall clock was CEST while Django's TIME_ZONE is UTC, and the run happened to fall in the ~2h window after local midnight but before UTC midnight, so datetime.date.today() in the test setup disagreed with timezone.now() by a day). Not a regression; reproducible on 4.2 in the same window. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… releases - djangorestframework 3.15.2 -> 3.18.0 (3.18.0's own metadata now requires django>=5.2) - django-debug-toolbar 5.1.0 -> 7.1.1 - django-modeltranslation 0.18.11 -> 0.20.3 Only django-debug-toolbar needed a Janeway-side fix, and it wasn't a simple version incompatibility so much as a new requirement the package introduced: 7.x added a persistent SQL history store backed by a real Django model (debug_toolbar.models.HistoryEntry), which requires the app to be registered in INSTALLED_APPS. Janeway's test settings (core/janeway_global_settings.py) never listed 'debug_toolbar' in INSTALLED_APPS -- only core/dev_settings.py did -- even though core/urls.py has always conditionally included debug_toolbar.urls whenever settings.IN_TEST_RUNNER is true. This was a latent gap that 5.1.0 tolerated silently and 7.1.1 does not. Fixes in core/janeway_global_settings.py: - Add 'debug_toolbar' to INSTALLED_APPS when IN_TEST_RUNNER, mirroring the existing dev_settings.py behaviour for DEBUG mode. - debug_toolbar.apps.DebugToolbarConfig.ready() now calls settings.MIGRATION_MODULES.setdefault(app_name, None). Janeway's SkipMigrations helper (used to skip migrations under the test runner) subclasses collections.abc.Mapping, which has no setdefault(). Added a setdefault() that mirrors the class's existing 'every key is present and reads as None' semantics. - Silence the resulting debug_toolbar.W001 system check (DebugToolbarMiddleware missing from MIDDLEWARE) -- intentional, since the middleware itself is still only enabled via dev_settings.py; the app is only registered here for its model. Full suite: 1295/1295 tests considered, same 3 pre-existing NewsItemOrderingTest failures as the prior commit (clock-artifact, unrelated to these packages). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…o >= 5.1 Phase 4 intentionally left src/cms/models.py and src/core/model_utils.py on CheckConstraint(check=...) since django-upgrade's check_constraint_condition fixer targets Django's CheckConstraint(condition=) replacement, only valid from Django 5.1. Now that Django is 5.2.17, re-ran the fixer scoped to exactly those two files: django-upgrade --target-version 5.2 src/cms/models.py src/core/model_utils.py The three migration files that also use CheckConstraint(check=...) were deliberately excluded and remain untouched, since migrations freeze historical state and shouldn't be rewritten: - cms/migrations/0022_navigationitem_nav_item_has_either_link_or_sub_nav.py - core/migrations/0104_location_organization_affiliation.py - submission/migrations/0085_creditrecord_and_more.py Full suite: 1295/1295 tests considered, same 3 pre-existing clock-artifact NewsItemOrderingTest failures, unaffected by this change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
USE_L10N has been a no-op since Django 4.0 (localized formatting is always enabled) and Django 5.0 removed it from django.conf.global_settings entirely -- Janeway's USE_L10N = False no longer has any effect. Removed per the migration plan's explicit cleanup note rather than leaving inert configuration behind. Full suite: 1295/1295 tests considered, same 3 pre-existing clock-artifact NewsItemOrderingTest failures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Formatting fixup for the DynamicChoiceField.formfield() line changed in the Django 5.2 bump commit (ffc4c31). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- dependencies: Django>=4.2 -> Django>=5.2. The codebase now relies on Django 5.1+ APIs (e.g. CheckConstraint(condition=...) in cms/models.py and core/model_utils.py), so declaring a >=4.2 floor was already factually wrong. - tool.tox.testenv.deps: Django==4.2 -> Django==5.2.17. This tox env installs this pin *and* file:requirements.txt (which pins Django==5.2.17) together; left at 4.2 it was a straight conflicting duplicate pin that would make 'make tox' fail dependency resolution outright, not just run against a stale Django. Not touched, flagged for separate follow-up: this file's requires-python = ">=3.9" and the tox env_list's "py39" entry are now inconsistent with Django 5.2's own Requires-Python: >=3.10 -- tox's py39 env will fail to install Django 5.2 at all. Left alone since Python-floor changes are Phase 6's remit per the migration plan, not this phase's. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Django 5.2 itself requires Python >=3.10, and this migration's own target range is Python 3.10-3.13. pyproject.toml still claimed >=3.9 and tox's env_list still tested py39, which is no longer valid. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
[tool.ruff]'s target-version was still py39, missed by the prior commit that fixed requires-python/tox to >=3.10. Bumped to py310 for consistency - ruff's target-version only affects which syntax modernizations it's allowed to suggest, so this is a config-only change. ruff format --check . remains clean (1252 files) - the only ruff check actually part of this project's CI contract per CLAUDE.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…pins Switched requirements.txt/dev-requirements.txt from exact '==' pins to '~=' (compatible-release) specifiers, at whatever precision each package's version already had (~=X.Y.Z where a patch segment exists, ~=X.Y for 2-segment versions like idna/pytz/packaging/docutils/ django-bootstrap4). This lets future 'pip install'/'pip install -U' runs pick up patch/compatible releases automatically without a manual pin bump, while still refusing anything that isn't declared compatible (a minor/major bump still requires an explicit version-string edit). pyproject.toml's own duplicate Django tox pin was updated to match, for the same reason it was kept in sync with requirements.txt during the Phase 5 Django bump. Three deliberate exceptions, kept as exact pins: - django-hCaptcha and pdfkit: both have standing leave-completely- untouched decisions from this migration (Phase 2 and the migration plan's scope notes, respectively) - kept exact rather than have their notation drift from what those decisions describe, even though neither has a newer release to float to today regardless. - pdfminer.six: version is a single calendar-date integer (20260107, no dotted release segments), which PEP 440's ~= operator can't syntactically apply to (requires at least two release segments) - kept exact. Verified this is behavior-neutral right now, not a hidden version bump: reinstalled from the updated files without --upgrade and confirmed no PyPI package resolved to a different version (only the 4 editable git installs rebuilt in place, which pip always does regardless of pinning style). Full suite re-run after: 1295 tests, OK. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- CI matrix now tests 3.11-3.14 (was 3.9-3.12) - pyproject.toml requires-python and ruff target-version bumped to 3.11 - tox env_list updated to py311-py314 - Dockerfile.base, .readthedocs.yml and .lando.yml base images bumped to 3.11 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add support for Django 5.2