Skip to content

update core dependencies & toolchain - #451

Merged
mik3y merged 30 commits into
mainfrom
mikey/dep-updates-2026
Aug 3, 2026
Merged

update core dependencies & toolchain#451
mik3y merged 30 commits into
mainfrom
mikey/dep-updates-2026

Conversation

@mik3y

@mik3y mik3y commented Aug 2, 2026

Copy link
Copy Markdown
Member

Part of #452. In this change:

  • toolchain updates (switch to uv, ruff, etc)
  • update major dependencies (django -> 5.2, etc)
  • fix breakages and bit rot
  • add tests for backup/restore

mik3y added 14 commits August 2, 2026 16:05
- rewrite pyproject.toml to PEP 621 + uv dependency-groups; hatchling backend
- replace poetry.lock with uv.lock; drive fixtures via `uv run`
- keep existing pins (Django 3.2) so this is a pure tooling swap, no upgrades
- pin django-crispy-forms==1.14.0 to match the prior resolved lock
- fall back to in-process fakeredis under pytest when REDIS_URL is unset
- REDIS_URL now required only outside pytest; CI still exercises real redis
- DictToProtoMessage referenced an undefined `util.datetime_to_iso8601str`
  (a NameError if ever hit); use datetime.isoformat() instead
- latent since it only triggers on datetime proto fields, which the Stats
  message (its sole caller) does not have
- replace black + flake8 + isort with ruff (check + format), mirroring the
  taplistio config: line-length 100, select E/F/I, ignore E501, preserve quotes
- move dev tooling to the uv dev group; drop flake8/isort config from setup.cfg
- reformat the tree and clear unused imports and other lint nits
- keep `signal_handlers` import in core apps ready() (registers receivers) and
  the late template-dirs import behind `# noqa`; exclude generated *_pb2.py
- re-export proto exceptions from kbapi via explicit imports + __all__
- swap sync_with_poetry / isort / black hooks for sync-with-uv + ruff-pre-commit
- add pre-commit to the uv dev group; pin the hook to the locked ruff 0.16.1
- drop the py2 `from builtins import *` in bin/kegbot so the hooks pass
- Django 3.2 -> 5.2 LTS, with matching django-cors-headers, django-redis,
  django-rq/rq, and DRF bumps
- django-crispy-forms 1.x -> 2.x plus the crispy-bootstrap4 template pack
- drop the unmaintained django-bootstrap-pagination and pytz
- settings: migrate DEFAULT_FILE_STORAGE/STATICFILES_STORAGE to STORAGES,
  set the crispy bootstrap4 pack, add scheme to CSRF_TRUSTED_ORIGINS
- switch SESSION_SERIALIZER to JSONSerializer (pickle serializer removed);
  existing sessions are invalidated on upgrade
- code: url() -> re_path(), get_storage_class() -> default_storage,
  timezone.utc -> datetime.timezone.utc, pytz -> zoneinfo
- guard _keg_pre_save against reverse-relation use on an unsaved keg
- django-rq now defers enqueue to on_db_commit; use auto commit mode under
  pytest so synchronous jobs still run inline within TestCase
- add a Bootstrap 3 pagination include backed by Django's own Paginator
  (elided page range + querystring-preserving links)
- swap the 10 {% bootstrap_paginate %} usages over to the new include
- the admin-user step called authenticate() but discarded the result, so the
  freshly-created admin was never actually signed in
- IsSetupMiddleware stubbed the session for all /setup paths; only stub it
  until the session table exists (created by the wizard's first migrate step),
  so login() can establish a real session for the admin step
- add a test asserting the new admin ends up authenticated
- run_server now launches `waitress-serve` (honors $PORT, --threads tunable)
- drop the gunicorn config, the deprecated run_gunicorn shim, and the
  "gunicorn" INSTALLED_APPS entry
- removes the gevent C-extension dependency ahead of the Python 3.14 bump
- target Python 3.14 (requires-python, .python-version, pre-commit); enable
  ruff UP (pyupgrade) at py314
- protobuf 3.20 -> 6.x; FieldDescriptor.label -> is_repeated/is_required
- remove python-gflags; reduce pykeg.proto.kbapi to its exception re-exports
  (the gflags-based client now lives only in the kegbot-api project)
- fix 3.14 removals: pkgutil.get_loader -> importlib.util.find_spec,
  datetime.utcnow() -> now(UTC); fakeredis FakeConnection -> FakeRedisConnection
- f-strings, `class X:` over `class X(object)`, drop `from builtins`/`__future__`
  shims, and other pyupgrade rewrites across the tree
- base python:3.14-slim; install deps with uv into the system environment
  (cached lockfile layer), dropping poetry and the rust/cryptography dance
- keep the MySQL/Postgres/Pillow build libraries the drivers need
- pybuild: uv + python 3.14, a sqlite/mysql/postgres matrix with a redis
  service, run migrations + collectstatic + pytest + ruff; trigger on main
- docker: trigger on main, drop the armv7 target and its qemu/tmpfs
  workaround, refresh action versions and use $GITHUB_OUTPUT
@mik3y
mik3y force-pushed the mikey/dep-updates-2026 branch from 3fee315 to 1398c78 Compare August 2, 2026 16:08
- add upgrade notes under a "Current version (unreleased)" heading
- set the package version to a clear pre-release marker (2.0.0.dev0)
- keep the demo-site server_version current in the v2 API tests so the version
  bump doesn't trip the "upgrade required" gate
@mik3y
mik3y force-pushed the mikey/dep-updates-2026 branch from 1398c78 to 9cf5eb3 Compare August 3, 2026 04:13
mik3y added 13 commits August 3, 2026 04:18
- pykeg imports packaging.version directly, but it previously arrived only as
  a transitive dev dependency; the no-dev docker image exposed the gap
- verified by import-walking every non-test module and running collectstatic
  in a --no-dev environment
- FlowMeter/FlowToggle have no Meta.ordering, and the tests indexed a lazy
  unordered queryset that re-executes after the disconnect/connect updates;
  postgres relocates updated rows, reshuffling the result
- pin the tap's own meter/toggle via the OneToOne relation instead
- clears the "Node.js 20 is deprecated" annotations; all five bumps are pure
  runtime updates with no input changes we rely on
- includes login-action, which only runs on push so hadn't warned yet
- docker "latest" now follows the newest non-prerelease semver tag (via
  metadata-action `flavor: latest=auto`) instead of every merge to main
- merges to main publish only "dev", so sites pulling latest stay on the
  newest tagged release
- remove future, httplib2, oauthlib, requests-oauthlib (nothing imports them)
  and the direct pilkit pin (still present transitively via django-imagekit)
- fakeredis is only imported under pytest, so it belongs in the dev group
- freezegun stays a runtime dep: generate_fixtures uses it outside tests
- re-verified the no-dev (docker) environment via import-walk + collectstatic
- the old config still ran poetry against the deleted poetry.lock
- add a `docs` dependency group (sphinx, furo, sphinx-issues, sphinx-autobuild)
  and build via uv on RTD
- use stock furo from PyPI instead of the dormant Kegbot fork; the only theme
  options in use (light/dark logo) are standard, and the build passes with -W
- docs use no autodoc, so the project (and its C-extension deps) is not
  installed for the docs build
- these used the pre-1.10 optparse style and could not receive
  positional args on modern Django
- restore dispatches on backup_format; format 1 loads the per-table
  fixture dumps through the ORM into a freshly migrated schema, then
  finalizes version + stats, so no separate upgrade step is needed
- media/zip files are now opened in binary mode (restore was broken
  for images on python 3)
- verified end-to-end against a real 2014 v1.1.0 site backup
- apps.get_models() includes models without tables (django_rq
  dashboard), which broke the legacy restore test on postgres
- media files and the zip were written through text-mode handles
- os.path.join was passed a tuple when recursing into media subdirs
- is_installed compared str against bytes output on mysql and postgres
- postgres restore/erase never passed PGPASSWORD
- the backup command imported get_storage_class, removed in Django 5.1

None of this was covered by tests (backup_test.py is skipped); the new
legacy-upgrade CI workflow exercises it against real databases.
- restores testdata/legacy-backups/kegbot-v1.3-{mysql,postgres}.zip,
  runs kegbot upgrade, and verifies the result against the demo fixture
- self-skips until the frozen zips are committed
- frozen zips mean future migrations are always tested against a
  database as it existed at v1.3
- kegbot backup/restore/erase shell out to mysqldump/mysql/pg_dump/psql,
  which were missing from the image
- bin/generate-legacy-backups.sh builds v1.3-site backup zips from
  testdata/demo-site.json using the server image against pinned
  mysql:8/postgres:16, then they are committed as frozen fixtures
mik3y added 2 commits August 3, 2026 16:49
- mariadb 11.4+ clients (debian's default-mysql-client) verify server
  certs by default and reject the self-signed certs mysql servers
  auto-generate; keep TLS but skip verification, matching the Django
  connection
- the loose- prefix makes oracle mysql clients warn instead of exit on
  the unknown option
- generated with bin/generate-legacy-backups.sh (demo-site data,
  stored server_version 1.3.0)
- activates the 'Upgrade from v1.3' CI jobs
@mik3y
mik3y merged commit fdb4257 into main Aug 3, 2026
6 checks passed
@mik3y
mik3y deleted the mikey/dep-updates-2026 branch August 3, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant