diff --git a/CLAUDE.md b/CLAUDE.md index abf26d5..c1c696c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,11 +4,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -This is the Python Ireland (python.ie / pycon.ie) website, built with Django 5.2 and Wagtail CMS 7.2. It manages content for the Python Ireland community including meetups, sponsors, speakers, and PyCon talks/sessions. +This is the Python Ireland (python.ie / pycon.ie) website, built with Django 6.0 and Wagtail CMS 7.2. It manages content for the Python Ireland community including meetups, sponsors, speakers, and PyCon talks/sessions. ### Python Version -This project requires **Python 3.13**. All code must be compatible with Python 3.13. When developing locally without Docker, ensure you are using Python 3.13.x. +This project requires **Python 3.13.11** (or any Python 3.13.x). All code must be compatible with Python 3.13. When developing locally without Docker, ensure you are using Python 3.13.x. ## Architecture @@ -42,8 +42,8 @@ Always specify settings module: `--settings=pythonie.settings.dev` (or `tests`, ### Key Dependencies -- Django ~5.2.0 -- Wagtail ~7.2.0 (CMS framework) +- Django 6.0 +- Wagtail 7.2.1 (CMS framework) - Redis (caching, configured via `REDISCLOUD_URL`) - WhiteNoise (static file serving) - boto3/django-storages (S3 integration) @@ -260,7 +260,7 @@ Tests use `pythonie.settings.tests` which configures SQLite and mock Redis. Run ### Deployment -The project is hosted on Heroku. +The project is hosted on Heroku using the **heroku-24** stack with PostgreSQL 17. ### Upgrading Wagtail diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94f5dcc..9cd82ed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -158,7 +158,7 @@ refactor/simplify-sponsor-model ### Python -- **Python version**: 3.13 (strict requirement) +- **Python version**: 3.13.11 (or any Python 3.13.x - strict requirement) - **Formatter**: Ruff - **Line length**: 88 characters (Ruff default) - **Imports**: Sorted automatically by Ruff diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a02b45f..e7f29e3 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -22,16 +22,16 @@ ### Tech Stack -- **Framework**: Django 5.2.8 -- **CMS**: Wagtail 7.2 -- **Python**: 3.13 (required) +- **Framework**: Django 6.0 +- **CMS**: Wagtail 7.2.1 +- **Python**: 3.13.11 (or any Python 3.13.x - required) - **Database**: PostgreSQL 17 (prod and dev via Docker) - **Cache**: Redis 6.2 - **Storage**: AWS S3 (prod), Local (dev) - **Server**: Gunicorn (prod), Runserver (dev) - **Containerization**: Docker + docker-compose - **Automation**: Task (Taskfile.yaml) -- **Deployment**: Heroku +- **Deployment**: Heroku (heroku-24 stack) ### Project Statistics @@ -105,7 +105,7 @@ pythonie/ ### Prerequisites -- Python 3.13 (required) +- Python 3.13.11 (or any Python 3.13.x - required) - Docker + docker-compose - Task (or Make) - Git @@ -1441,6 +1441,7 @@ pythonie/pythonie/wsgi.py # WSGI application --- **Last updated**: 2025 -**Django Version**: 5.2.8 -**Wagtail Version**: 7.2 -**Python Version**: 3.13 +**Django Version**: 6.0 +**Wagtail Version**: 7.2.1 +**Python Version**: 3.13.11 +**Heroku Stack**: heroku-24 diff --git a/README.md b/README.md index d7e0d24..7aad389 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Python Ireland Website -Website for Python Ireland (python.ie / pycon.ie) community, built with Django 5.2 and Wagtail CMS 7.2. Manages meetups, sponsors, speakers, and conference sessions. +Website for Python Ireland (python.ie / pycon.ie) community, built with Django 6.0 and Wagtail CMS 7.2. Manages meetups, sponsors, speakers, and conference sessions. ## Prerequisites @@ -213,7 +213,7 @@ export MEETUP_KEY=your_meetup_api_key # Get from https://secure.meetup.com/meet ## Deployment -The project is deployed on Heroku. Use Task commands for database operations: +The project is deployed on Heroku using the **heroku-24** stack with PostgreSQL 17. Use Task commands for database operations: ```bash # View backups diff --git a/pythonie/core/factories.py b/pythonie/core/factories.py index daaf4fc..1ae74f1 100644 --- a/pythonie/core/factories.py +++ b/pythonie/core/factories.py @@ -1,11 +1,11 @@ import factory -from factory.django import DjangoModelFactory from django.utils import timezone - -from core.models import HomePage, SimplePage +from factory.django import DjangoModelFactory from meetups.models import Meetup from sponsors.models import SponsorshipLevel +from core.models import HomePage, SimplePage + class SponsorshipLevelFactory(DjangoModelFactory): class Meta: diff --git a/pythonie/core/management/commands/generate_sample_data.py b/pythonie/core/management/commands/generate_sample_data.py index b5f8c7c..afc46b5 100644 --- a/pythonie/core/management/commands/generate_sample_data.py +++ b/pythonie/core/management/commands/generate_sample_data.py @@ -1,7 +1,12 @@ from django.core.management.base import BaseCommand from wagtail.models import Page, Site -from core.factories import SponsorshipLevelFactory, MeetupFactory, HomePageFactory, SimplePageFactory +from core.factories import ( + HomePageFactory, + MeetupFactory, + SimplePageFactory, + SponsorshipLevelFactory, +) from core.models import HomePage, SimplePage @@ -84,7 +89,9 @@ def _create_page(self, parent, title, slug, body=None): self.stdout.write(f" {title} already exists") return SimplePage.objects.get(slug=slug) - page = SimplePageFactory.build(title=title, slug=slug, body=body or [], show_in_menus=True) + page = SimplePageFactory.build( + title=title, slug=slug, body=body or [], show_in_menus=True + ) parent.add_child(instance=page) self.stdout.write(self.style.SUCCESS(f"Created {title}")) return page @@ -92,37 +99,52 @@ def _create_page(self, parent, title, slug, body=None): def _get_home_content(self): return [ {"type": "heading", "value": "Introduction"}, - {"type": "paragraph", "value": ( - "
Python Ireland is the Irish organisation representing the various chapters of Python users. " - "We organise meet ups and events for software developers, students, academics and anyone who wants " - "to learn the language. One of our aims is to help grow and diversify the Python community in Ireland. " - "We also develop and foster links with other Python based communities overseas.
" - )}, + { + "type": "paragraph", + "value": ( + "Python Ireland is the Irish organisation representing the various chapters of Python users. " + "We organise meet ups and events for software developers, students, academics and anyone who wants " + "to learn the language. One of our aims is to help grow and diversify the Python community in Ireland. " + "We also develop and foster links with other Python based communities overseas.
" + ), + }, {"type": "heading", "value": "PyCon Ireland 2025"}, - {"type": "paragraph", "value": ( - "We are thrilled to announce PyCon Ireland 2025, taking place in Dublin " - "on November 15th and 16th! Join us at the UCD O'Reilly Hall for this exciting event.
" - )}, - {"type": "paragraph", "value": ( - "PyCon Ireland 2025 will feature two talk tracks and two workshop tracks on both days. " - "Your ticket includes breakfast and lunch. Join us Saturday evening for networking!
" - )}, - {"type": "paragraph", "value": ( - "Please adhere to our Code of Conduct. " - "Check Terms and conditions for details.
" - )}, + { + "type": "paragraph", + "value": ( + "We are thrilled to announce PyCon Ireland 2025, taking place in Dublin " + "on November 15th and 16th! Join us at the UCD O'Reilly Hall for this exciting event.
" + ), + }, + { + "type": "paragraph", + "value": ( + "PyCon Ireland 2025 will feature two talk tracks and two workshop tracks on both days. " + "Your ticket includes breakfast and lunch. Join us Saturday evening for networking!
" + ), + }, + { + "type": "paragraph", + "value": ( + "Please adhere to our Code of Conduct. " + "Check Terms and conditions for details.
" + ), + }, {"type": "paragraph", "value": "See you at PyCon Ireland 2025!
"}, ] def _get_meetups_content(self): return [ {"type": "heading", "value": "Python Ireland Meetups"}, - {"type": "paragraph", "value": ( - "Join us at our regular meetups! We hold events every month.
" - "Join us at our regular meetups! We hold events every month.
" + "We will be having a meetup in June. More details to follow." "
If you are interested in speaking, please submit your " @@ -62,7 +63,7 @@ def _first_result(self): "description": description, "name": "Python Ireland meetup", "event_url": ( - "http://www.meetup.com/pythonireland/" "events/221078098/" + "http://www.meetup.com/pythonireland/events/221078098/" ), "headcount": 0, "time": 1433957400000, @@ -125,7 +126,7 @@ def test_update_first_run(self, mock_get_content): self.assertEqual(meetup.visibility, "public") self.assertEqual( meetup.event_url, - ("http://www.meetup.com/" "pythonireland/events/221078098/"), + ("http://www.meetup.com/pythonireland/events/221078098/"), ) @patch("meetups.utils.get_content") diff --git a/pythonie/pythonie/settings/base.py b/pythonie/pythonie/settings/base.py index abdd645..3d7ff5d 100644 --- a/pythonie/pythonie/settings/base.py +++ b/pythonie/pythonie/settings/base.py @@ -7,6 +7,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.7/ref/settings/ """ + import os from os.path import abspath, dirname, join diff --git a/pythonie/pythonie/urls.py b/pythonie/pythonie/urls.py index fcbae32..a78678f 100644 --- a/pythonie/pythonie/urls.py +++ b/pythonie/pythonie/urls.py @@ -1,12 +1,12 @@ import os from django.conf import settings -from django.urls import path, re_path from django.conf.urls import include from django.conf.urls.static import static from django.contrib import admin -from wagtail.admin import urls as wagtailadmin_urls +from django.urls import path, re_path from wagtail import urls as wagtail_urls +from wagtail.admin import urls as wagtailadmin_urls # from wagtail.search import urls as wagtailsearch_urls from wagtail.documents import urls as wagtaildocs_urls diff --git a/pythonie/pythonie/wsgi.py b/pythonie/pythonie/wsgi.py index 3dde89b..4dcbcf7 100644 --- a/pythonie/pythonie/wsgi.py +++ b/pythonie/pythonie/wsgi.py @@ -6,10 +6,11 @@ For more information on this file, see https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ """ + import os -from django.core.wsgi import get_wsgi_application from dj_static import Cling +from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pythonie.settings.production") diff --git a/pythonie/speakers/admin.py b/pythonie/speakers/admin.py index b380284..d4a6d93 100644 --- a/pythonie/speakers/admin.py +++ b/pythonie/speakers/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from speakers.models import Speaker, Session, Room +from speakers.models import Room, Session, Speaker class RoomAdmin(admin.ModelAdmin): diff --git a/pythonie/speakers/management/commands/import-sessionize.py b/pythonie/speakers/management/commands/import-sessionize.py index 803923d..a565e1f 100644 --- a/pythonie/speakers/management/commands/import-sessionize.py +++ b/pythonie/speakers/management/commands/import-sessionize.py @@ -4,10 +4,9 @@ import numpy as np import pandas as pd from django.core.management.base import BaseCommand, CommandParser -from django.utils.text import slugify from wagtail.models import Page -from speakers.models import Speaker, Room, Session +from speakers.models import Room, Session, Speaker log = logging.getLogger("import-sessionize") @@ -98,7 +97,6 @@ def save_sessions(self, options): parent_page = Page.objects.get(id=145).specific for index, row in sessions.iterrows(): - if row[SessionHeaders.Room] is np.nan: continue diff --git a/pythonie/speakers/management/commands/update-sessionize-json-stream.py b/pythonie/speakers/management/commands/update-sessionize-json-stream.py index 65374bd..7709fd4 100644 --- a/pythonie/speakers/management/commands/update-sessionize-json-stream.py +++ b/pythonie/speakers/management/commands/update-sessionize-json-stream.py @@ -2,10 +2,10 @@ import pydantic import requests -from django.core.management import BaseCommand, CommandParser +from django.core.management import BaseCommand from wagtail.models import Page -from speakers.models import Speaker, Session, Room +from speakers.models import Room, Session, Speaker class SessionModel(pydantic.BaseModel): @@ -132,7 +132,7 @@ def save_session( session.save() session.save_revision().publish() print( - f'{incoming_session.id} {incoming_session.title} {created and "CREATED" or "UPDATED"}' + f"{incoming_session.id} {incoming_session.title} {created and 'CREATED' or 'UPDATED'}" ) def save_room(self, incoming_room: RoomModel) -> Room: diff --git a/pythonie/speakers/migrations/0002_talkspage.py b/pythonie/speakers/migrations/0002_talkspage.py index 33df73a..5cfa177 100644 --- a/pythonie/speakers/migrations/0002_talkspage.py +++ b/pythonie/speakers/migrations/0002_talkspage.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("speakers", "0001_initial"), ] diff --git a/pythonie/speakers/migrations/0003_auto_20220929_1828.py b/pythonie/speakers/migrations/0003_auto_20220929_1828.py index bb8040e..acc8f0a 100644 --- a/pythonie/speakers/migrations/0003_auto_20220929_1828.py +++ b/pythonie/speakers/migrations/0003_auto_20220929_1828.py @@ -1,11 +1,10 @@ # Generated by Django 3.2.15 on 2022-09-29 18:28 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ("wagtailcore", "0066_collection_management_permissions"), ("speakers", "0002_talkspage"), diff --git a/pythonie/speakers/migrations/0004_alter_session_room.py b/pythonie/speakers/migrations/0004_alter_session_room.py index d08884c..f273e3c 100644 --- a/pythonie/speakers/migrations/0004_alter_session_room.py +++ b/pythonie/speakers/migrations/0004_alter_session_room.py @@ -5,15 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('speakers', '0003_auto_20220929_1828'), + ("speakers", "0003_auto_20220929_1828"), ] operations = [ migrations.AlterField( - model_name='session', - name='room', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='speakers.room'), + model_name="session", + name="room", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="speakers.room" + ), ), ] diff --git a/pythonie/speakers/models.py b/pythonie/speakers/models.py index 472811d..7e7376b 100644 --- a/pythonie/speakers/models.py +++ b/pythonie/speakers/models.py @@ -1,8 +1,5 @@ -import json import logging -import requests -from django.conf import settings from django.db import models from wagtail.admin.panels import FieldPanel from wagtail.models import Page diff --git a/pythonie/speakers/templatetags/speaker_tags.py b/pythonie/speakers/templatetags/speaker_tags.py index 0055506..6755e4e 100644 --- a/pythonie/speakers/templatetags/speaker_tags.py +++ b/pythonie/speakers/templatetags/speaker_tags.py @@ -1,4 +1,5 @@ from django import template + from speakers.models import Speaker register = template.Library() diff --git a/pythonie/sponsors/migrations/0001_initial.py b/pythonie/sponsors/migrations/0001_initial.py index 03d3ade..04a9a7b 100644 --- a/pythonie/sponsors/migrations/0001_initial.py +++ b/pythonie/sponsors/migrations/0001_initial.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("wagtailimages", "0005_make_filter_spec_unique"), ] diff --git a/pythonie/sponsors/migrations/0002_restructure_sponsor.py b/pythonie/sponsors/migrations/0002_restructure_sponsor.py index ac58664..0e0788e 100644 --- a/pythonie/sponsors/migrations/0002_restructure_sponsor.py +++ b/pythonie/sponsors/migrations/0002_restructure_sponsor.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("sponsors", "0001_initial"), ] diff --git a/pythonie/sponsors/migrations/0003_sponsorshiplevel.py b/pythonie/sponsors/migrations/0003_sponsorshiplevel.py index 90ba107..05c8c49 100644 --- a/pythonie/sponsors/migrations/0003_sponsorshiplevel.py +++ b/pythonie/sponsors/migrations/0003_sponsorshiplevel.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("sponsors", "0002_restructure_sponsor"), ] diff --git a/pythonie/sponsors/migrations/0004_auto_20150726_1412.py b/pythonie/sponsors/migrations/0004_auto_20150726_1412.py index dc3967d..3ed8b10 100644 --- a/pythonie/sponsors/migrations/0004_auto_20150726_1412.py +++ b/pythonie/sponsors/migrations/0004_auto_20150726_1412.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ("sponsors", "0003_sponsorshiplevel"), ] diff --git a/pythonie/sponsors/test_sponsors.py b/pythonie/sponsors/test_sponsors.py index eb3d297..ea9ff96 100644 --- a/pythonie/sponsors/test_sponsors.py +++ b/pythonie/sponsors/test_sponsors.py @@ -1,5 +1,6 @@ from django.test import TestCase from model_mommy import mommy + from sponsors.models import Sponsor, SponsorshipLevel