From 306607d5b99b6eca6ae2c1e726d8eb32b9b2ca1b Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 9 Sep 2021 15:15:44 +0200 Subject: Fixed #32365 -- Made zoneinfo the default timezone implementation. Thanks to Adam Johnson, Aymeric Augustin, David Smith, Mariusz Felisiak, Nick Pope, and Paul Ganssle for reviews. --- tests/admin_views/tests.py | 18 +- tests/admin_widgets/tests.py | 9 +- tests/datetimes/tests.py | 13 +- tests/db_functions/datetime/test_extract_trunc.py | 198 ++++++++++++---------- tests/migrations/test_writer.py | 26 +++ tests/settings_tests/tests.py | 20 ++- tests/timezones/tests.py | 43 +++-- tests/utils_tests/test_autoreload.py | 9 +- tests/utils_tests/test_timezone.py | 94 ++++++---- 9 files changed, 272 insertions(+), 158 deletions(-) (limited to 'tests') diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index a8524379f8..9f9e924b62 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -5,15 +5,15 @@ import unittest from unittest import mock from urllib.parse import parse_qsl, urljoin, urlparse -import pytz - try: import zoneinfo except ImportError: - try: - from backports import zoneinfo - except ImportError: - zoneinfo = None + from backports import zoneinfo + +try: + import pytz +except ImportError: + pytz = None from django.contrib import admin from django.contrib.admin import AdminSite, ModelAdmin @@ -73,10 +73,10 @@ MULTIPART_ENCTYPE = 'enctype="multipart/form-data"' def make_aware_datetimes(dt, iana_key): """Makes one aware datetime for each supported time zone provider.""" - yield pytz.timezone(iana_key).localize(dt, is_dst=None) + yield dt.replace(tzinfo=zoneinfo.ZoneInfo(iana_key)) - if zoneinfo is not None: - yield dt.replace(tzinfo=zoneinfo.ZoneInfo(iana_key)) + if pytz is not None: + yield pytz.timezone(iana_key).localize(dt, is_dst=None) class AdminFieldExtractionMixin: diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 1bb4c9a9b1..3a57227caa 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -4,7 +4,10 @@ import re from datetime import datetime, timedelta from importlib import import_module -import pytz +try: + import zoneinfo +except ImportError: + from backports import zoneinfo from django import forms from django.conf import settings @@ -967,8 +970,8 @@ class DateTimePickerShortcutsSeleniumTests(AdminWidgetSeleniumTestCase): error_margin = timedelta(seconds=10) # If we are neighbouring a DST, we add an hour of error margin. - tz = pytz.timezone('America/Chicago') - utc_now = datetime.now(pytz.utc) + tz = zoneinfo.ZoneInfo('America/Chicago') + utc_now = datetime.now(zoneinfo.ZoneInfo('UTC')) tz_yesterday = (utc_now - timedelta(days=1)).astimezone(tz).tzname() tz_tomorrow = (utc_now + timedelta(days=1)).astimezone(tz).tzname() if tz_yesterday != tz_tomorrow: diff --git a/tests/datetimes/tests.py b/tests/datetimes/tests.py index 7f98032e0a..95828f8e09 100644 --- a/tests/datetimes/tests.py +++ b/tests/datetimes/tests.py @@ -1,9 +1,14 @@ import datetime +import unittest -import pytz +try: + import pytz +except ImportError: + pytz = None -from django.test import TestCase, override_settings +from django.test import TestCase, ignore_warnings, override_settings from django.utils import timezone +from django.utils.deprecation import RemovedInDjango50Warning from .models import Article, Category, Comment @@ -91,7 +96,9 @@ class DateTimesTests(TestCase): qs = Article.objects.datetimes('pub_date', 'second') self.assertEqual(qs[0], now) - @override_settings(USE_TZ=True, TIME_ZONE='UTC') + @unittest.skipUnless(pytz is not None, 'Test requires pytz') + @ignore_warnings(category=RemovedInDjango50Warning) + @override_settings(USE_TZ=True, TIME_ZONE='UTC', USE_DEPRECATED_PYTZ=True) def test_datetimes_ambiguous_and_invalid_times(self): sao = pytz.timezone('America/Sao_Paulo') utc = pytz.UTC diff --git a/tests/db_functions/datetime/test_extract_trunc.py b/tests/db_functions/datetime/test_extract_trunc.py index ced9da0c78..a129448470 100644 --- a/tests/db_functions/datetime/test_extract_trunc.py +++ b/tests/db_functions/datetime/test_extract_trunc.py @@ -1,14 +1,15 @@ +import unittest from datetime import datetime, timedelta, timezone as datetime_timezone -import pytz - try: import zoneinfo except ImportError: - try: - from backports import zoneinfo - except ImportError: - zoneinfo = None + from backports import zoneinfo + +try: + import pytz +except ImportError: + pytz = None from django.conf import settings from django.db.models import ( @@ -23,15 +24,24 @@ from django.db.models.functions import ( TruncYear, ) from django.test import ( - TestCase, override_settings, skipIfDBFeature, skipUnlessDBFeature, + TestCase, ignore_warnings, override_settings, skipIfDBFeature, + skipUnlessDBFeature, ) from django.utils import timezone +from django.utils.deprecation import RemovedInDjango50Warning from ..models import Author, DTModel, Fan -ZONE_CONSTRUCTORS = (pytz.timezone,) -if zoneinfo is not None: - ZONE_CONSTRUCTORS += (zoneinfo.ZoneInfo,) +HAS_PYTZ = pytz is not None +if not HAS_PYTZ: + needs_pytz = unittest.skip('Test requires pytz') +else: + def needs_pytz(f): + return f + +ZONE_CONSTRUCTORS = (zoneinfo.ZoneInfo,) +if HAS_PYTZ: + ZONE_CONSTRUCTORS += (pytz.timezone,) def truncate_to(value, kind, tzinfo=None): @@ -98,8 +108,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 10) end_datetime = datetime(2016, 6, 15, 14, 10) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) @@ -135,8 +145,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 10) end_datetime = datetime(2016, 6, 15, 14, 10) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) @@ -158,8 +168,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 10) end_datetime = datetime(2016, 6, 15, 14, 10) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) @@ -181,8 +191,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) @@ -280,8 +290,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -319,8 +329,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -339,8 +349,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -359,14 +369,14 @@ class DateFunctionTests(TestCase): def test_extract_iso_year_func_boundaries(self): end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + end_datetime = timezone.make_aware(end_datetime) week_52_day_2014 = datetime(2014, 12, 27, 13, 0) # Sunday week_1_day_2014_2015 = datetime(2014, 12, 31, 13, 0) # Wednesday week_53_day_2015 = datetime(2015, 12, 31, 13, 0) # Thursday if settings.USE_TZ: - week_1_day_2014_2015 = timezone.make_aware(week_1_day_2014_2015, is_dst=False) - week_52_day_2014 = timezone.make_aware(week_52_day_2014, is_dst=False) - week_53_day_2015 = timezone.make_aware(week_53_day_2015, is_dst=False) + week_1_day_2014_2015 = timezone.make_aware(week_1_day_2014_2015) + week_52_day_2014 = timezone.make_aware(week_52_day_2014) + week_53_day_2015 = timezone.make_aware(week_53_day_2015) days = [week_52_day_2014, week_1_day_2014_2015, week_53_day_2015] obj_1_iso_2014 = self.create_model(week_52_day_2014, end_datetime) obj_1_iso_2015 = self.create_model(week_1_day_2014_2015, end_datetime) @@ -397,8 +407,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -417,8 +427,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -437,8 +447,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -458,8 +468,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 8, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -477,13 +487,13 @@ class DateFunctionTests(TestCase): def test_extract_quarter_func_boundaries(self): end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + end_datetime = timezone.make_aware(end_datetime) last_quarter_2014 = datetime(2014, 12, 31, 13, 0) first_quarter_2015 = datetime(2015, 1, 1, 13, 0) if settings.USE_TZ: - last_quarter_2014 = timezone.make_aware(last_quarter_2014, is_dst=False) - first_quarter_2015 = timezone.make_aware(first_quarter_2015, is_dst=False) + last_quarter_2014 = timezone.make_aware(last_quarter_2014) + first_quarter_2015 = timezone.make_aware(first_quarter_2015) dates = [last_quarter_2014, first_quarter_2015] self.create_model(last_quarter_2014, end_datetime) self.create_model(first_quarter_2015, end_datetime) @@ -498,15 +508,15 @@ class DateFunctionTests(TestCase): def test_extract_week_func_boundaries(self): end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + end_datetime = timezone.make_aware(end_datetime) week_52_day_2014 = datetime(2014, 12, 27, 13, 0) # Sunday week_1_day_2014_2015 = datetime(2014, 12, 31, 13, 0) # Wednesday week_53_day_2015 = datetime(2015, 12, 31, 13, 0) # Thursday if settings.USE_TZ: - week_1_day_2014_2015 = timezone.make_aware(week_1_day_2014_2015, is_dst=False) - week_52_day_2014 = timezone.make_aware(week_52_day_2014, is_dst=False) - week_53_day_2015 = timezone.make_aware(week_53_day_2015, is_dst=False) + week_1_day_2014_2015 = timezone.make_aware(week_1_day_2014_2015) + week_52_day_2014 = timezone.make_aware(week_52_day_2014) + week_53_day_2015 = timezone.make_aware(week_53_day_2015) days = [week_52_day_2014, week_1_day_2014_2015, week_53_day_2015] self.create_model(week_53_day_2015, end_datetime) @@ -525,8 +535,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -551,8 +561,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -586,8 +596,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -606,8 +616,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -626,8 +636,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -646,8 +656,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) @@ -752,8 +762,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'year') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -786,10 +796,10 @@ class DateFunctionTests(TestCase): last_quarter_2015 = truncate_to(datetime(2015, 12, 31, 14, 10, 50, 123), 'quarter') first_quarter_2016 = truncate_to(datetime(2016, 1, 1, 14, 10, 50, 123), 'quarter') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) - last_quarter_2015 = timezone.make_aware(last_quarter_2015, is_dst=False) - first_quarter_2016 = timezone.make_aware(first_quarter_2016, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) + last_quarter_2015 = timezone.make_aware(last_quarter_2015) + first_quarter_2016 = timezone.make_aware(first_quarter_2016) self.create_model(start_datetime=start_datetime, end_datetime=end_datetime) self.create_model(start_datetime=end_datetime, end_datetime=start_datetime) self.create_model(start_datetime=last_quarter_2015, end_datetime=end_datetime) @@ -825,8 +835,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'month') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -857,8 +867,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'week') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -881,8 +891,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -909,8 +919,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -937,8 +947,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 26) # 0 microseconds. end_datetime = datetime(2015, 6, 15, 14, 30, 26, 321) if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.assertIs( DTModel.objects.filter( @@ -962,8 +972,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'day') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -986,8 +996,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'hour') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -1018,8 +1028,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'minute') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -1050,8 +1060,8 @@ class DateFunctionTests(TestCase): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'second') if settings.USE_TZ: - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) self.assertQuerysetEqual( @@ -1085,9 +1095,9 @@ class DateFunctionTests(TestCase): fan_since_2 = datetime(2015, 2, 3, 15, 0, 0) fan_since_3 = datetime(2017, 2, 3, 15, 0, 0) if settings.USE_TZ: - fan_since_1 = timezone.make_aware(fan_since_1, is_dst=False) - fan_since_2 = timezone.make_aware(fan_since_2, is_dst=False) - fan_since_3 = timezone.make_aware(fan_since_3, is_dst=False) + fan_since_1 = timezone.make_aware(fan_since_1) + fan_since_2 = timezone.make_aware(fan_since_2) + fan_since_3 = timezone.make_aware(fan_since_3) Fan.objects.create(author=author_1, name='Tom', fan_since=fan_since_1) Fan.objects.create(author=author_1, name='Emma', fan_since=fan_since_2) Fan.objects.create(author=author_2, name='Isabella', fan_since=fan_since_3) @@ -1113,9 +1123,9 @@ class DateFunctionTests(TestCase): datetime_2 = datetime(2001, 3, 5) datetime_3 = datetime(2002, 1, 3) if settings.USE_TZ: - datetime_1 = timezone.make_aware(datetime_1, is_dst=False) - datetime_2 = timezone.make_aware(datetime_2, is_dst=False) - datetime_3 = timezone.make_aware(datetime_3, is_dst=False) + datetime_1 = timezone.make_aware(datetime_1) + datetime_2 = timezone.make_aware(datetime_2) + datetime_3 = timezone.make_aware(datetime_3) obj_1 = self.create_model(datetime_1, datetime_3) obj_2 = self.create_model(datetime_2, datetime_1) obj_3 = self.create_model(datetime_3, datetime_2) @@ -1144,8 +1154,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): def test_extract_func_with_timezone(self): start_datetime = datetime(2015, 6, 15, 23, 30, 1, 321) end_datetime = datetime(2015, 6, 16, 13, 11, 27, 123) - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) delta_tzinfo_pos = datetime_timezone(timedelta(hours=5)) delta_tzinfo_neg = datetime_timezone(timedelta(hours=-5, minutes=17)) @@ -1203,8 +1213,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): def test_extract_func_explicit_timezone_priority(self): start_datetime = datetime(2015, 6, 15, 23, 30, 1, 321) end_datetime = datetime(2015, 6, 16, 13, 11, 27, 123) - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) for melb in self.get_timezones('Australia/Melbourne'): @@ -1233,8 +1243,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): def test_trunc_timezone_applied_before_truncation(self): start_datetime = datetime(2016, 1, 1, 1, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) for melb, pacific in zip( @@ -1263,6 +1273,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): self.assertEqual(model.melb_time, melb_start_datetime.time()) self.assertEqual(model.pacific_time, pacific_start_datetime.time()) + @needs_pytz + @ignore_warnings(category=RemovedInDjango50Warning) def test_trunc_ambiguous_and_invalid_times(self): sao = pytz.timezone('America/Sao_Paulo') utc = timezone.utc @@ -1294,8 +1306,8 @@ class DateFunctionWithTimeZoneTests(DateFunctionTests): """ start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) - start_datetime = timezone.make_aware(start_datetime, is_dst=False) - end_datetime = timezone.make_aware(end_datetime, is_dst=False) + start_datetime = timezone.make_aware(start_datetime) + end_datetime = timezone.make_aware(end_datetime) self.create_model(start_datetime, end_datetime) self.create_model(end_datetime, start_datetime) diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py index 471194ffc2..f21c560208 100644 --- a/tests/migrations/test_writer.py +++ b/tests/migrations/test_writer.py @@ -10,6 +10,16 @@ import sys import uuid from unittest import mock +try: + import zoneinfo +except ImportError: + from backports import zoneinfo + +try: + import pytz +except ImportError: + pytz = None + import custom_migration_operations.more_operations import custom_migration_operations.operations @@ -503,6 +513,22 @@ class WriterTests(SimpleTestCase): ) ) + self.assertSerializedResultEqual( + datetime.datetime(2012, 1, 1, 2, 1, tzinfo=zoneinfo.ZoneInfo('Europe/Paris')), + ( + "datetime.datetime(2012, 1, 1, 1, 1, tzinfo=utc)", + {'import datetime', 'from django.utils.timezone import utc'}, + ) + ) + if pytz: + self.assertSerializedResultEqual( + pytz.timezone('Europe/Paris').localize(datetime.datetime(2012, 1, 1, 2, 1)), + ( + "datetime.datetime(2012, 1, 1, 1, 1, tzinfo=utc)", + {'import datetime', 'from django.utils.timezone import utc'}, + ) + ) + def test_serialize_fields(self): self.assertSerializedFieldEqual(models.CharField(max_length=255)) self.assertSerializedResultEqual( diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py index 899059764e..e958a984fa 100644 --- a/tests/settings_tests/tests.py +++ b/tests/settings_tests/tests.py @@ -4,7 +4,10 @@ import unittest from types import ModuleType, SimpleNamespace from unittest import mock -from django.conf import ENVIRONMENT_VARIABLE, LazySettings, Settings, settings +from django.conf import ( + ENVIRONMENT_VARIABLE, USE_DEPRECATED_PYTZ_DEPRECATED_MSG, LazySettings, + Settings, settings, +) from django.core.exceptions import ImproperlyConfigured from django.http import HttpRequest from django.test import ( @@ -348,6 +351,21 @@ class SettingsTests(SimpleTestCase): finally: del sys.modules['fake_settings_module'] + def test_use_deprecated_pytz_deprecation(self): + settings_module = ModuleType('fake_settings_module') + settings_module.USE_DEPRECATED_PYTZ = True + settings_module.USE_TZ = True + sys.modules['fake_settings_module'] = settings_module + try: + with self.assertRaisesMessage(RemovedInDjango50Warning, USE_DEPRECATED_PYTZ_DEPRECATED_MSG): + Settings('fake_settings_module') + finally: + del sys.modules['fake_settings_module'] + + holder = LazySettings() + with self.assertRaisesMessage(RemovedInDjango50Warning, USE_DEPRECATED_PYTZ_DEPRECATED_MSG): + holder.configure(USE_DEPRECATED_PYTZ=True) + class TestComplexSettingOverride(SimpleTestCase): def setUp(self): diff --git a/tests/timezones/tests.py b/tests/timezones/tests.py index 98c5cdac33..71bc94f490 100644 --- a/tests/timezones/tests.py +++ b/tests/timezones/tests.py @@ -5,15 +5,15 @@ from contextlib import contextmanager from unittest import SkipTest, skipIf from xml.dom.minidom import parseString -import pytz - try: import zoneinfo except ImportError: - try: - from backports import zoneinfo - except ImportError: - zoneinfo = None + from backports import zoneinfo + +try: + import pytz +except ImportError: + pytz = None from django.contrib.auth.models import User from django.core import serializers @@ -61,9 +61,9 @@ UTC = timezone.utc EAT = timezone.get_fixed_timezone(180) # Africa/Nairobi ICT = timezone.get_fixed_timezone(420) # Asia/Bangkok -ZONE_CONSTRUCTORS = (pytz.timezone,) -if zoneinfo is not None: - ZONE_CONSTRUCTORS += (zoneinfo.ZoneInfo,) +ZONE_CONSTRUCTORS = (zoneinfo.ZoneInfo,) +if pytz is not None: + ZONE_CONSTRUCTORS += (pytz.timezone,) def get_timezones(key): @@ -363,6 +363,23 @@ class NewDatabaseTests(TestCase): self.assertEqual(Event.objects.filter(dt__in=(prev, dt, next)).count(), 1) self.assertEqual(Event.objects.filter(dt__range=(prev, next)).count(), 1) + @ignore_warnings(category=RemovedInDjango50Warning) + def test_connection_timezone(self): + tests = [ + (False, None, datetime.timezone), + (False, 'Africa/Nairobi', zoneinfo.ZoneInfo), + ] + if pytz is not None: + tests += [ + (True, None, datetime.timezone), + (True, 'Africa/Nairobi', pytz.BaseTzInfo), + ] + for use_pytz, connection_tz, expected_type in tests: + with self.subTest(use_pytz=use_pytz, connection_tz=connection_tz): + with self.settings(USE_DEPRECATED_PYTZ=use_pytz): + with override_database_connection_timezone(connection_tz): + self.assertIsInstance(connection.timezone, expected_type) + def test_query_convert_timezones(self): # Connection timezone is equal to the current timezone, datetime # shouldn't be converted. @@ -921,7 +938,7 @@ class TemplateTests(SimpleTestCase): tpl = Template("{% load tz %}{{ dt|timezone:tz }}") ctx = Context({ 'dt': datetime.datetime(2011, 9, 1, 13, 20, 30), - 'tz': pytz.timezone('Europe/Paris'), + 'tz': tz, }) self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00") @@ -994,11 +1011,15 @@ class TemplateTests(SimpleTestCase): }) self.assertEqual(tpl.render(ctx), "2011-09-01T12:20:30+02:00") + @ignore_warnings(category=RemovedInDjango50Warning) def test_timezone_templatetag_invalid_argument(self): with self.assertRaises(TemplateSyntaxError): Template("{% load tz %}{% timezone %}{% endtimezone %}").render() - with self.assertRaises(pytz.UnknownTimeZoneError): + with self.assertRaises(zoneinfo.ZoneInfoNotFoundError): Template("{% load tz %}{% timezone tz %}{% endtimezone %}").render(Context({'tz': 'foobar'})) + if pytz is not None: + with override_settings(USE_DEPRECATED_PYTZ=True), self.assertRaises(pytz.UnknownTimeZoneError): + Template("{% load tz %}{% timezone tz %}{% endtimezone %}").render(Context({'tz': 'foobar'})) @skipIf(sys.platform == 'win32', "Windows uses non-standard time zone names") def test_get_current_timezone_templatetag(self): diff --git a/tests/utils_tests/test_autoreload.py b/tests/utils_tests/test_autoreload.py index 1e43cecea9..7c28a9d4d0 100644 --- a/tests/utils_tests/test_autoreload.py +++ b/tests/utils_tests/test_autoreload.py @@ -14,7 +14,10 @@ from pathlib import Path from subprocess import CompletedProcess from unittest import mock, skip, skipIf -import pytz +try: + import zoneinfo +except ImportError: + from backports import zoneinfo import django.__main__ from django.apps.registry import Apps @@ -247,7 +250,7 @@ class TestChildArguments(SimpleTestCase): class TestUtilities(SimpleTestCase): def test_is_django_module(self): for module, expected in ( - (pytz, False), + (zoneinfo, False), (sys, False), (autoreload, True) ): @@ -256,7 +259,7 @@ class TestUtilities(SimpleTestCase): def test_is_django_path(self): for module, expected in ( - (pytz.__file__, False), + (zoneinfo.__file__, False), (contextlib.__file__, False), (autoreload.__file__, True) ): diff --git a/tests/utils_tests/test_timezone.py b/tests/utils_tests/test_timezone.py index 0972135dcc..a61bb4acb0 100644 --- a/tests/utils_tests/test_timezone.py +++ b/tests/utils_tests/test_timezone.py @@ -2,41 +2,58 @@ import datetime import unittest from unittest import mock -import pytz +try: + import pytz +except ImportError: + pytz = None try: import zoneinfo except ImportError: - try: - from backports import zoneinfo - except ImportError: - zoneinfo = None + from backports import zoneinfo -from django.test import SimpleTestCase, override_settings +from django.test import SimpleTestCase, ignore_warnings, override_settings from django.utils import timezone +from django.utils.deprecation import RemovedInDjango50Warning -CET = pytz.timezone("Europe/Paris") +PARIS_ZI = zoneinfo.ZoneInfo('Europe/Paris') EAT = timezone.get_fixed_timezone(180) # Africa/Nairobi ICT = timezone.get_fixed_timezone(420) # Asia/Bangkok UTC = datetime.timezone.utc -HAS_ZONEINFO = zoneinfo is not None +HAS_PYTZ = pytz is not None +if not HAS_PYTZ: + CET = None + PARIS_IMPLS = (PARIS_ZI,) -if not HAS_ZONEINFO: - PARIS_ZI = None - PARIS_IMPLS = (CET,) - - needs_zoneinfo = unittest.skip("Test requires zoneinfo") + needs_pytz = unittest.skip('Test requires pytz') else: - PARIS_ZI = zoneinfo.ZoneInfo('Europe/Paris') - PARIS_IMPLS = (CET, PARIS_ZI) + CET = pytz.timezone('Europe/Paris') + PARIS_IMPLS = (PARIS_ZI, CET) - def needs_zoneinfo(f): + def needs_pytz(f): return f class TimezoneTests(SimpleTestCase): + def setUp(self): + # RemovedInDjango50Warning + timezone.get_default_timezone.cache_clear() + + def tearDown(self): + # RemovedInDjango50Warning + timezone.get_default_timezone.cache_clear() + + def test_default_timezone_is_zoneinfo(self): + self.assertIsInstance(timezone.get_default_timezone(), zoneinfo.ZoneInfo) + + @needs_pytz + @ignore_warnings(category=RemovedInDjango50Warning) + @override_settings(USE_DEPRECATED_PYTZ=True) + def test_setting_allows_fallback_to_pytz(self): + self.assertIsInstance(timezone.get_default_timezone(), pytz.BaseTzInfo) + def test_now(self): with override_settings(USE_TZ=True): self.assertTrue(timezone.is_aware(timezone.now())) @@ -173,13 +190,14 @@ class TimezoneTests(SimpleTestCase): timezone.make_aware(datetime.datetime(2011, 9, 1, 12, 20, 30), tz), datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=CEST)) - with self.assertRaises(ValueError): - timezone.make_aware(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET) - - if HAS_ZONEINFO: + if HAS_PYTZ: with self.assertRaises(ValueError): - timezone.make_aware(datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=PARIS_ZI), PARIS_ZI) + timezone.make_aware(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET) + + with self.assertRaises(ValueError): + timezone.make_aware(datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=PARIS_ZI), PARIS_ZI) + @needs_pytz def test_make_naive_pytz(self): self.assertEqual( timezone.make_naive(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET), @@ -192,7 +210,6 @@ class TimezoneTests(SimpleTestCase): with self.assertRaisesMessage(ValueError, 'make_naive() cannot be applied to a naive datetime'): timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30), CET) - @needs_zoneinfo def test_make_naive_zoneinfo(self): self.assertEqual( timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=PARIS_ZI), PARIS_ZI), @@ -204,6 +221,8 @@ class TimezoneTests(SimpleTestCase): datetime.datetime(2011, 9, 1, 12, 20, 30, fold=1) ) + @needs_pytz + @ignore_warnings(category=RemovedInDjango50Warning) def test_make_aware_pytz_ambiguous(self): # 2:30 happens twice, once before DST ends and once after ambiguous = datetime.datetime(2015, 10, 25, 2, 30) @@ -217,7 +236,6 @@ class TimezoneTests(SimpleTestCase): self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) - @needs_zoneinfo def test_make_aware_zoneinfo_ambiguous(self): # 2:30 happens twice, once before DST ends and once after ambiguous = datetime.datetime(2015, 10, 25, 2, 30) @@ -232,6 +250,8 @@ class TimezoneTests(SimpleTestCase): self.assertEqual(std.utcoffset(), datetime.timedelta(hours=1)) self.assertEqual(dst.utcoffset(), datetime.timedelta(hours=2)) + @needs_pytz + @ignore_warnings(category=RemovedInDjango50Warning) def test_make_aware_pytz_non_existent(self): # 2:30 never happened due to DST non_existent = datetime.datetime(2015, 3, 29, 2, 30) @@ -245,7 +265,6 @@ class TimezoneTests(SimpleTestCase): self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) - @needs_zoneinfo def test_make_aware_zoneinfo_non_existent(self): # 2:30 never happened due to DST non_existent = datetime.datetime(2015, 3, 29, 2, 30) @@ -260,6 +279,15 @@ class TimezoneTests(SimpleTestCase): self.assertEqual(std.utcoffset(), datetime.timedelta(hours=1)) self.assertEqual(dst.utcoffset(), datetime.timedelta(hours=2)) + def test_make_aware_is_dst_deprecation_warning(self): + msg = ( + 'The is_dst argument to make_aware(), used by the Trunc() ' + 'database functions and QuerySet.datetimes(), is deprecated as it ' + 'has no effect with zoneinfo time zones.' + ) + with self.assertRaisesMessage(RemovedInDjango50Warning, msg): + timezone.make_aware(datetime.datetime(2011, 9, 1, 13, 20, 30), EAT, is_dst=True) + def test_get_timezone_name(self): """ The _get_timezone_name() helper must return the offset for fixed offset @@ -271,15 +299,15 @@ class TimezoneTests(SimpleTestCase): # datetime.timezone, fixed offset with and without `name`. (datetime.timezone(datetime.timedelta(hours=10)), 'UTC+10:00'), (datetime.timezone(datetime.timedelta(hours=10), name='Etc/GMT-10'), 'Etc/GMT-10'), - # pytz, named and fixed offset. - (pytz.timezone('Europe/Madrid'), 'Europe/Madrid'), - (pytz.timezone('Etc/GMT-10'), '+10'), + # zoneinfo, named and fixed offset. + (zoneinfo.ZoneInfo('Europe/Madrid'), 'Europe/Madrid'), + (zoneinfo.ZoneInfo('Etc/GMT-10'), '+10'), ] - if HAS_ZONEINFO: + if HAS_PYTZ: tests += [ - # zoneinfo, named and fixed offset. - (zoneinfo.ZoneInfo('Europe/Madrid'), 'Europe/Madrid'), - (zoneinfo.ZoneInfo('Etc/GMT-10'), '+10'), + # pytz, named and fixed offset. + (pytz.timezone('Europe/Madrid'), 'Europe/Madrid'), + (pytz.timezone('Etc/GMT-10'), '+10'), ] for tz, expected in tests: with self.subTest(tz=tz, expected=expected): @@ -288,10 +316,6 @@ class TimezoneTests(SimpleTestCase): def test_get_default_timezone(self): self.assertEqual(timezone.get_default_timezone_name(), 'America/Chicago') - def test_get_default_timezone_utc(self): - with override_settings(USE_TZ=True, TIME_ZONE='UTC'): - self.assertIs(timezone.get_default_timezone(), timezone.utc) - def test_fixedoffset_timedelta(self): delta = datetime.timedelta(hours=1) self.assertEqual(timezone.get_fixed_timezone(delta).utcoffset(None), delta) -- cgit v1.3