5
5
import sys
6
6
import uuid
7
7
from decimal import ROUND_DOWN , ROUND_UP , Decimal
8
+ from unittest .mock import patch
8
9
9
10
import pytest
10
11
import pytz
21
22
)
22
23
from tests .models import UUIDForeignKeyTarget
23
24
25
+ if sys .version_info >= (3 , 9 ):
26
+ from zoneinfo import ZoneInfo
27
+ else :
28
+ from backports .zoneinfo import ZoneInfo
29
+
24
30
utc = datetime .timezone .utc
25
31
26
32
# Tests for helper functions.
@@ -651,15 +657,15 @@ class FieldValues:
651
657
"""
652
658
Base class for testing valid and invalid input values.
653
659
"""
654
- def test_valid_inputs (self ):
660
+ def test_valid_inputs (self , * args ):
655
661
"""
656
662
Ensure that valid values return the expected validated data.
657
663
"""
658
664
for input_value , expected_output in get_items (self .valid_inputs ):
659
665
assert self .field .run_validation (input_value ) == expected_output , \
660
666
'input value: {}' .format (repr (input_value ))
661
667
662
- def test_invalid_inputs (self ):
668
+ def test_invalid_inputs (self , * args ):
663
669
"""
664
670
Ensure that invalid values raise the expected validation error.
665
671
"""
@@ -669,7 +675,7 @@ def test_invalid_inputs(self):
669
675
assert exc_info .value .detail == expected_failure , \
670
676
'input value: {}' .format (repr (input_value ))
671
677
672
- def test_outputs (self ):
678
+ def test_outputs (self , * args ):
673
679
for output_value , expected_output in get_items (self .outputs ):
674
680
assert self .field .to_representation (output_value ) == expected_output , \
675
681
'output value: {}' .format (repr (output_value ))
@@ -1505,12 +1511,12 @@ class TestTZWithDateTimeField(FieldValues):
1505
1511
@classmethod
1506
1512
def setup_class (cls ):
1507
1513
# use class setup method, as class-level attribute will still be evaluated even if test is skipped
1508
- kolkata = pytz . timezone ('Asia/Kolkata' )
1514
+ kolkata = ZoneInfo ('Asia/Kolkata' )
1509
1515
1510
1516
cls .valid_inputs = {
1511
- '2016-12-19T10:00:00' : kolkata . localize ( datetime .datetime (2016 , 12 , 19 , 10 ) ),
1512
- '2016-12-19T10:00:00+05:30' : kolkata . localize ( datetime .datetime (2016 , 12 , 19 , 10 ) ),
1513
- datetime .datetime (2016 , 12 , 19 , 10 ): kolkata . localize ( datetime .datetime (2016 , 12 , 19 , 10 ) ),
1517
+ '2016-12-19T10:00:00' : datetime .datetime (2016 , 12 , 19 , 10 , tzinfo = kolkata ),
1518
+ '2016-12-19T10:00:00+05:30' : datetime .datetime (2016 , 12 , 19 , 10 , tzinfo = kolkata ),
1519
+ datetime .datetime (2016 , 12 , 19 , 10 ): datetime .datetime (2016 , 12 , 19 , 10 , tzinfo = kolkata ),
1514
1520
}
1515
1521
cls .invalid_inputs = {}
1516
1522
cls .outputs = {
@@ -1529,7 +1535,7 @@ class TestDefaultTZDateTimeField(TestCase):
1529
1535
@classmethod
1530
1536
def setup_class (cls ):
1531
1537
cls .field = serializers .DateTimeField ()
1532
- cls .kolkata = pytz . timezone ('Asia/Kolkata' )
1538
+ cls .kolkata = ZoneInfo ('Asia/Kolkata' )
1533
1539
1534
1540
def assertUTC (self , tzinfo ):
1535
1541
"""
@@ -1551,18 +1557,17 @@ def test_current_timezone(self):
1551
1557
self .assertUTC (self .field .default_timezone ())
1552
1558
1553
1559
1554
- @pytest .mark .skipif (pytz is None , reason = 'pytz not installed' )
1555
1560
@override_settings (TIME_ZONE = 'UTC' , USE_TZ = True )
1556
1561
class TestCustomTimezoneForDateTimeField (TestCase ):
1557
1562
1558
1563
@classmethod
1559
1564
def setup_class (cls ):
1560
- cls .kolkata = pytz . timezone ('Asia/Kolkata' )
1565
+ cls .kolkata = ZoneInfo ('Asia/Kolkata' )
1561
1566
cls .date_format = '%d/%m/%Y %H:%M'
1562
1567
1563
1568
def test_should_render_date_time_in_default_timezone (self ):
1564
1569
field = serializers .DateTimeField (default_timezone = self .kolkata , format = self .date_format )
1565
- dt = datetime .datetime (2018 , 2 , 8 , 14 , 15 , 16 , tzinfo = pytz . utc )
1570
+ dt = datetime .datetime (2018 , 2 , 8 , 14 , 15 , 16 , tzinfo = ZoneInfo ( "UTC" ) )
1566
1571
1567
1572
with override (self .kolkata ):
1568
1573
rendered_date = field .to_representation (dt )
@@ -1572,7 +1577,8 @@ def test_should_render_date_time_in_default_timezone(self):
1572
1577
assert rendered_date == rendered_date_in_timezone
1573
1578
1574
1579
1575
- class TestNaiveDayLightSavingTimeTimeZoneDateTimeField (FieldValues ):
1580
+ @pytest .mark .skipif (pytz is None , reason = "As Django 4.0 has deprecated pytz, this test should eventually be able to get removed." )
1581
+ class TestPytzNaiveDayLightSavingTimeTimeZoneDateTimeField (FieldValues ):
1576
1582
"""
1577
1583
Invalid values for `DateTimeField` with datetime in DST shift (non-existing or ambiguous) and timezone with DST.
1578
1584
Timezone America/New_York has DST shift from 2017-03-12T02:00:00 to 2017-03-12T03:00:00 and
@@ -1596,6 +1602,27 @@ def __str__(self):
1596
1602
field = serializers .DateTimeField (default_timezone = MockTimezone ())
1597
1603
1598
1604
1605
+ @patch ('rest_framework.utils.timezone.datetime_ambiguous' , return_value = True )
1606
+ class TestNaiveDayLightSavingTimeTimeZoneDateTimeField (FieldValues ):
1607
+ """
1608
+ Invalid values for `DateTimeField` with datetime in DST shift (non-existing or ambiguous) and timezone with DST.
1609
+ Timezone America/New_York has DST shift from 2017-03-12T02:00:00 to 2017-03-12T03:00:00 and
1610
+ from 2017-11-05T02:00:00 to 2017-11-05T01:00:00 in 2017.
1611
+ """
1612
+ valid_inputs = {}
1613
+ invalid_inputs = {
1614
+ '2017-03-12T02:30:00' : ['Invalid datetime for the timezone "America/New_York".' ],
1615
+ '2017-11-05T01:30:00' : ['Invalid datetime for the timezone "America/New_York".' ]
1616
+ }
1617
+ outputs = {}
1618
+
1619
+ class MockZoneInfoTimezone (datetime .tzinfo ):
1620
+ def __str__ (self ):
1621
+ return 'America/New_York'
1622
+
1623
+ field = serializers .DateTimeField (default_timezone = MockZoneInfoTimezone ())
1624
+
1625
+
1599
1626
class TestTimeField (FieldValues ):
1600
1627
"""
1601
1628
Valid and invalid values for `TimeField`.
0 commit comments