From efc4ccd7bc57dc6e1b11911f0e253e3a255e8ac9 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Jun 2025 21:19:28 -0300 Subject: [PATCH 1/2] refactor: don't mutate countries/timezones --- ietf/meeting/forms.py | 5 ----- ietf/meeting/models.py | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/ietf/meeting/forms.py b/ietf/meeting/forms.py index e1d1e90b8d..ec347082fc 100644 --- a/ietf/meeting/forms.py +++ b/ietf/meeting/forms.py @@ -38,11 +38,6 @@ from ietf.utils.validators import ( validate_file_size, validate_mime_type, validate_file_extension, validate_no_html_frame) -# need to insert empty option for use in ChoiceField -# countries.insert(0, ('', '-'*9 )) -countries.insert(0, ('', '-' * 9)) -timezones.insert(0, ('', '-' * 9)) - # ------------------------------------------------- # Helpers # ------------------------------------------------- diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index cc5241efa2..411405a14f 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -49,16 +49,16 @@ ) from ietf.utils.fields import MissingOkImageField -countries = list(pytz.country_names.items()) -countries.sort(key=lambda x: x[1]) - -timezones = [] -for name in pytz.common_timezones: - tzfn = os.path.join(settings.TZDATA_ICS_PATH, name + ".ics") - if not os.path.islink(tzfn): - timezones.append((name, name)) -timezones.sort() - +# Set up countries / timezones, including an empty choice for fields +EMPTY_CHOICE = ('', '-' * 9) +countries = [EMPTY_CHOICE] + sorted(pytz.country_names.items(), key=lambda x: x[1]) + +_tzdata_ics_path = Path(settings.TZDATA_ICS_PATH) +timezones = [EMPTY_CHOICE] + sorted( + (name, name) + for name in pytz.common_timezones + if not (_tzdata_ics_path / f"{name}.ics").is_symlink() +) class Meeting(models.Model): # number is either the number for IETF meetings, or some other From baa6507a0cb452d3873b20aeb183f4d2b7bd3b15 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Jun 2025 21:21:48 -0300 Subject: [PATCH 2/2] refactor: capitalize/make tuples to discourage mutation --- ietf/meeting/forms.py | 6 +++--- ietf/meeting/models.py | 21 +++++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ietf/meeting/forms.py b/ietf/meeting/forms.py index ec347082fc..b6b1a1591f 100644 --- a/ietf/meeting/forms.py +++ b/ietf/meeting/forms.py @@ -22,7 +22,7 @@ from ietf.doc.models import Document, State, NewRevisionDocEvent from ietf.group.models import Group from ietf.group.utils import groups_managed_by -from ietf.meeting.models import Session, Meeting, Schedule, countries, timezones, TimeSlot, Room +from ietf.meeting.models import Session, Meeting, Schedule, COUNTRIES, TIMEZONES, TimeSlot, Room from ietf.meeting.helpers import get_next_interim_number, make_materials_directories from ietf.meeting.helpers import is_interim_meeting_approved, get_next_agenda_name from ietf.message.models import Message @@ -135,12 +135,12 @@ class InterimMeetingModelForm(forms.ModelForm): approved = forms.BooleanField(required=False) city = forms.CharField(max_length=255, required=False) city.widget.attrs['placeholder'] = "City" - country = forms.ChoiceField(choices=countries, required=False) + country = forms.ChoiceField(choices=COUNTRIES, required=False) country.widget.attrs['class'] = "select2-field" country.widget.attrs['data-max-entries'] = 1 country.widget.attrs['data-placeholder'] = "Country" country.widget.attrs['data-minimum-input-length'] = 0 - time_zone = forms.ChoiceField(choices=timezones) + time_zone = forms.ChoiceField(choices=TIMEZONES) time_zone.widget.attrs['class'] = "select2-field" time_zone.widget.attrs['data-max-entries'] = 1 time_zone.widget.attrs['data-minimum-input-length'] = 0 diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index 411405a14f..75436f790a 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -50,16 +50,21 @@ from ietf.utils.fields import MissingOkImageField # Set up countries / timezones, including an empty choice for fields -EMPTY_CHOICE = ('', '-' * 9) -countries = [EMPTY_CHOICE] + sorted(pytz.country_names.items(), key=lambda x: x[1]) +EMPTY_CHOICE = ("", "-" * 9) +COUNTRIES = (EMPTY_CHOICE,) + tuple( + sorted(pytz.country_names.items(), key=lambda x: x[1]) +) _tzdata_ics_path = Path(settings.TZDATA_ICS_PATH) -timezones = [EMPTY_CHOICE] + sorted( - (name, name) - for name in pytz.common_timezones - if not (_tzdata_ics_path / f"{name}.ics").is_symlink() +TIMEZONES = (EMPTY_CHOICE,) + tuple( + sorted( + (name, name) + for name in pytz.common_timezones + if not (_tzdata_ics_path / f"{name}.ics").is_symlink() + ) ) + class Meeting(models.Model): # number is either the number for IETF meetings, or some other # identifier for interim meetings/IESG retreats/liaison summits/... @@ -72,11 +77,11 @@ class Meeting(models.Model): days = models.IntegerField(default=7, null=False, validators=[MinValueValidator(1)], help_text="The number of days the meeting lasts") city = models.CharField(blank=True, max_length=255) - country = models.CharField(blank=True, max_length=2, choices=countries) + country = models.CharField(blank=True, max_length=2, choices=COUNTRIES) # We can't derive time-zone from country, as there are some that have # more than one timezone, and the pytz module doesn't provide timezone # lookup information for all relevant city/country combinations. - time_zone = models.CharField(max_length=255, choices=timezones, default='UTC') + time_zone = models.CharField(max_length=255, choices=TIMEZONES, default='UTC') idsubmit_cutoff_day_offset_00 = models.IntegerField(blank=True, default=settings.IDSUBMIT_DEFAULT_CUTOFF_DAY_OFFSET_00, help_text = "The number of days before the meeting start date when the submission of -00 drafts will be closed.")