Skip to content

Commit b938925

Browse files
anandoleecopybara-github
authored andcommitted
Add type check when convert datetime to Timestamp and convert timedelta to duration.
The original code may raises AttributeError when assign wrong type to Timestamp/Duration. Will raise TypeError instead. PiperOrigin-RevId: 797464099
1 parent 8efdbbb commit b938925

File tree

4 files changed

+29
-21
lines changed

4 files changed

+29
-21
lines changed

python/google/protobuf/internal/duration_test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ def test_duration_add_annotation(self):
9393
# Duration + Duration
9494
self.assertEqual(dr + dr2, dr2 + dr)
9595

96+
def test_assign_datetime_to_duration(self):
97+
message = well_known_types_test_pb2.WKTMessage()
98+
with self.assertRaises(TypeError):
99+
message.optional_duration = datetime.datetime.now()
100+
96101

97102
if __name__ == '__main__':
98103
unittest.main()

python/google/protobuf/internal/timestamp_test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ def test_timestamp_add_annotation(self):
9090
# Timestamp + Duration and Duration + Timestamp
9191
self.assertEqual(ts + msg.optional_duration, msg.optional_duration + ts)
9292

93+
def test_assign_duration_to_timestamp(self):
94+
message = well_known_types_test_pb2.WKTMessage()
95+
with self.assertRaises(TypeError):
96+
message.optional_timestamp = datetime.timedelta(microseconds=123)
97+
9398

9499
if __name__ == '__main__':
95100
unittest.main()

python/google/protobuf/internal/well_known_types.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -279,14 +279,13 @@ def FromDatetime(self, dt):
279279
# manipulated into a long value of seconds. During the conversion from
280280
# struct_time to long, the source date in UTC, and so it follows that the
281281
# correct transformation is calendar.timegm()
282-
try:
283-
seconds = calendar.timegm(dt.utctimetuple())
284-
nanos = dt.microsecond * _NANOS_PER_MICROSECOND
285-
except AttributeError as e:
286-
raise AttributeError(
287-
'Fail to convert to Timestamp. Expected a datetime like '
288-
'object got {0} : {1}'.format(type(dt).__name__, e)
289-
) from e
282+
if not isinstance(dt, datetime.datetime):
283+
raise TypeError(
284+
'Fail to convert to Timestamp. Expected a datetime object '
285+
'got {0}'.format(type(dt).__name__)
286+
)
287+
seconds = calendar.timegm(dt.utctimetuple())
288+
nanos = dt.microsecond * _NANOS_PER_MICROSECOND
290289
_CheckTimestampValid(seconds, nanos)
291290
self.seconds = seconds
292291
self.nanos = nanos
@@ -445,16 +444,15 @@ def ToTimedelta(self) -> datetime.timedelta:
445444

446445
def FromTimedelta(self, td):
447446
"""Converts timedelta to Duration."""
448-
try:
449-
self._NormalizeDuration(
450-
td.seconds + td.days * _SECONDS_PER_DAY,
451-
td.microseconds * _NANOS_PER_MICROSECOND,
447+
if not isinstance(td, datetime.timedelta):
448+
raise TypeError(
449+
'Fail to convert to Duration. Expected a timedelta object '
450+
'got {0}'.format(type(td).__name__)
452451
)
453-
except AttributeError as e:
454-
raise AttributeError(
455-
'Fail to convert to Duration. Expected a timedelta like '
456-
'object got {0}: {1}'.format(type(td).__name__, e)
457-
) from e
452+
self._NormalizeDuration(
453+
td.seconds + td.days * _SECONDS_PER_DAY,
454+
td.microseconds * _NANOS_PER_MICROSECOND,
455+
)
458456

459457
def _internal_assign(self, td):
460458
self.FromTimedelta(td)

python/google/protobuf/internal/well_known_types_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -540,10 +540,10 @@ def testInvalidTimestamp(self):
540540
self.assertRaisesRegex(ValueError, 'Timestamp is not valid',
541541
message.FromSeconds, -62135596801)
542542
msg = well_known_types_test_pb2.WKTMessage()
543-
with self.assertRaises(AttributeError):
543+
with self.assertRaises(TypeError):
544544
msg.optional_timestamp = 1
545545

546-
with self.assertRaises(AttributeError):
546+
with self.assertRaises(TypeError):
547547
msg2 = well_known_types_test_pb2.WKTMessage(optional_timestamp=1)
548548

549549
with self.assertRaises(TypeError):
@@ -606,10 +606,10 @@ def testInvalidDuration(self):
606606
message.ToJsonString,
607607
)
608608
msg = well_known_types_test_pb2.WKTMessage()
609-
with self.assertRaises(AttributeError):
609+
with self.assertRaises(TypeError):
610610
msg.optional_duration = 1
611611

612-
with self.assertRaises(AttributeError):
612+
with self.assertRaises(TypeError):
613613
msg2 = well_known_types_test_pb2.WKTMessage(optional_duration=1)
614614

615615
with self.assertRaises(TypeError):

0 commit comments

Comments
 (0)