Skip to content

Commit 5f022ac

Browse files
authored
Upgrade django to 5.2, python to 3.13 (boostorg#1915)
1 parent 1ec3cba commit 5f022ac

26 files changed

+207
-130
lines changed

.github/workflows/actions-gcp.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525

2626
services:
2727
postgres:
28-
image: postgres:12
28+
image: postgres:16
2929
env:
3030
POSTGRES_USER: postgres
3131
POSTGRES_PASSWORD: postgres
@@ -44,10 +44,10 @@ jobs:
4444
with:
4545
fetch-depth: 0
4646

47-
- name: Set up Python 3.11
47+
- name: Set up Python 3.13
4848
uses: actions/setup-python@v5
4949
with:
50-
python-version: 3.11
50+
python-version: 3.13
5151

5252
- uses: actions/cache@v4
5353
with:
@@ -133,10 +133,10 @@ jobs:
133133
run: |
134134
git fetch --depth=1 origin +refs/tags/*:refs/tags/* || true
135135
136-
- name: Set up Python 3.11
136+
- name: Set up Python 3.13
137137
uses: actions/setup-python@v5
138138
with:
139-
python-version: 3.11
139+
python-version: 3.13
140140

141141
- name: Install Python dependencies
142142
run: |

.github/workflows/actions.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
services:
1717
postgres:
18-
image: postgres:12
18+
image: postgres:16
1919
env:
2020
POSTGRES_USER: postgres
2121
POSTGRES_PASSWORD: postgres
@@ -34,10 +34,10 @@ jobs:
3434
with:
3535
fetch-depth: 0
3636

37-
- name: Set up Python 3.11
37+
- name: Set up Python 3.13
3838
uses: actions/setup-python@v5
3939
with:
40-
python-version: 3.11
40+
python-version: 3.13
4141

4242
- uses: actions/cache@v4
4343
with:
@@ -85,10 +85,10 @@ jobs:
8585
run: |
8686
git fetch --depth=1 origin +refs/tags/*:refs/tags/* || true
8787
88-
- name: Set up Python 3.11
88+
- name: Set up Python 3.13
8989
uses: actions/setup-python@v5
9090
with:
91-
python-version: 3.11
91+
python-version: 3.13
9292

9393
- name: Install Python dependencies
9494
run: |

.pre-commit-config.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
default_language_version:
2-
python: python3.11
2+
python: python3.13
33

44
exclude: .*migrations\/.*|static\/img\/.*|static\/animations\/.*|static\/js\/boost-gecko\/.*|kube\/boost\/templates\/.*\.yaml
55

66
repos:
7+
- repo: https://github.com/adamchainz/django-upgrade
8+
rev: "1.27.0"
9+
hooks:
10+
- id: django-upgrade
11+
args: [--target-version, "5.2"] # Replace with Django version
712
- repo: https://github.com/pre-commit/pre-commit-hooks
813
rev: v5.0.0
914
hooks:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Links:
1313

1414
## Local Development Setup
1515

16-
This project will use Python 3.11, Docker, and Docker Compose.
16+
This project will use Python 3.13, Docker, and Docker Compose.
1717

1818
Instructions to install those packages are included in [development_setup_notes.md](docs/development_setup_notes.md).
1919

core/calendar.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ def get_calendar(min_time=None, single_events=True, order_by="startTime"):
2020
https://developers.google.com/calendar/api/v3/reference/events/list
2121
"""
2222
if not min_time:
23-
min_time = (
24-
datetime.datetime.utcnow().isoformat() + "Z"
25-
) # 'Z' indicates UTC time
26-
23+
# 'Z' indicates UTC time
24+
min_time = datetime.datetime.now(datetime.timezone.utc).isoformat() + "Z"
2725
url = f"https://www.googleapis.com/calendar/v3/calendars/{settings.BOOST_CALENDAR}/events?key={settings.CALENDAR_API_KEY}&timeMin={min_time}&singleEvents={single_events}&orderBy={order_by}"
2826

2927
headers = {"Accept": "application/json"}

core/migrations/0003_sitesettings_and_more.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class Migration(migrations.Migration):
2828
migrations.AddConstraint(
2929
model_name="sitesettings",
3030
constraint=models.CheckConstraint(
31-
check=models.Q(("id", 1)), name="core_sitesettings_single_instance"
31+
condition=models.Q(("id", 1)), name="core_sitesettings_single_instance"
3232
),
3333
),
3434
migrations.AlterModelOptions(

core/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class Meta:
7272
# check constraint to only allow id=1 to exist
7373
models.CheckConstraint(
7474
name="%(app_label)s_%(class)s_single_instance",
75-
check=models.Q(id=1),
75+
condition=models.Q(id=1),
7676
),
7777
]
7878
verbose_name_plural = "Site Settings"

core/views.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22

3+
import requests
34
from django.utils import timezone
45

56
from urllib.parse import urljoin
@@ -16,11 +17,14 @@
1617
HttpResponse,
1718
HttpResponseNotFound,
1819
HttpResponseRedirect,
20+
HttpRequest,
1921
)
2022
from django.shortcuts import redirect
2123
from django.template.loader import render_to_string
2224
from django.urls import reverse
25+
from django.utils.decorators import method_decorator
2326
from django.views import View
27+
from django.views.decorators.cache import never_cache
2428
from django.views.generic import TemplateView
2529

2630
from config.settings import ENABLE_DB_CACHE
@@ -942,3 +946,57 @@ def get(self, request, requested_version):
942946
if requested_version == "release":
943947
new_path = "/libraries/"
944948
return HttpResponseRedirect(new_path)
949+
950+
951+
@method_decorator(never_cache, name="dispatch")
952+
class QRCodeView(View):
953+
"""Handles QR code urls, sending them to Plausible, then redirecting to the desired url.
954+
955+
QR code urls are formatted /qrc/<campaign_identifier>/desired/path/to/content/, and will
956+
result in a redirect to /desired/path/to/content/.
957+
958+
E.g. https://www.boost.org/qrc/pv-01/library/latest/beast/ will send this full url to Plausible,
959+
then redirect to https://www.boost.org/library/latest/beast/
960+
"""
961+
962+
def get(self, request: HttpRequest, campaign_identifier: str, main_path: str = ""):
963+
absolute_url = request.build_absolute_uri(request.path)
964+
referrer = request.headers.get("referer", "")
965+
user_agent = request.headers.get("user-agent", "")
966+
967+
plausible_payload = {
968+
"name": "pageview",
969+
"domain": "qrc.boost.org",
970+
"url": absolute_url,
971+
"referrer": referrer,
972+
}
973+
974+
headers = {"Content-Type": "application/json", "User-Agent": user_agent}
975+
976+
client_ip = request.headers.get("x-forwarded-for", "").split(",")[0].strip()
977+
client_ip = client_ip or request.META.get("REMOTE_ADDR")
978+
979+
if client_ip:
980+
headers["X-Forwarded-For"] = client_ip
981+
982+
try:
983+
requests.post(
984+
"https://plausible.io/api/event",
985+
json=plausible_payload,
986+
headers=headers,
987+
timeout=2.0,
988+
)
989+
except Exception as e:
990+
# Don’t interrupt the redirect - just log it
991+
logger.error(f"Plausible event post failed: {e}")
992+
993+
# Now that we've sent the request url to plausible, we can redirect to the main_path
994+
# Preserve the original querystring, if any.
995+
# Example: /qrc/3/library/latest/algorithm/?x=1 -> /library/latest/algorithm/?x=1
996+
# `main_path` is everything after qrc/<campaign>/ thanks to <path:main_path>.
997+
redirect_path = "/" + main_path if main_path else "/"
998+
qs = request.META.get("QUERY_STRING")
999+
if qs:
1000+
redirect_path = f"{redirect_path}?{qs}"
1001+
1002+
return HttpResponseRedirect(redirect_path)

docker/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# syntax = docker/dockerfile:experimental
22

3-
FROM python:3.11-slim AS builder-py
3+
FROM python:3.13-slim AS builder-py
44

55
ARG LOCAL_DEVELOPMENT
66

@@ -42,7 +42,7 @@ RUN yarn build
4242

4343

4444
# Final image.
45-
FROM python:3.11-slim AS release
45+
FROM python:3.13-slim AS release
4646

4747
RUN apt update && apt install -y git libpq-dev ruby ruby-dev && rm -rf /var/lib/apt/lists/*
4848

docs/dependencies.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,14 @@
77
1. Run `just pip-compile`, which will add the dependency to `requirements.txt`
88
1. Run `just rebuild` to rebuild your Docker image to include the new dependencies
99
2. Run `just up` and continue with development
10+
11+
## Upgrading dependencies
12+
13+
To upgrade all dependencies to their latest versions, run:
14+
15+
1. `just pip-compile-upgrade`.
16+
2. Get the django version from requirements.txt and set the `DJANGO_VERSION` value in /justfile
17+
3. Update the `--target-version` args value for django-upgrade in .pre-commit-config.yaml to match
18+
3. In a venv with installed packages run `just run-django-upgrade` to upgrade python code.
19+
4. `just build` to create new docker images.
20+
5. Tear down docker containers and restart with the newly built images, then test.

0 commit comments

Comments
 (0)