|
13 | 13 | import uuid |
14 | 14 | from datetime import timezone |
15 | 15 | from typing import Optional, List |
| 16 | +from dateutil.parser import parse as parsedatestring |
16 | 17 |
|
17 | 18 | import dateutil.parser |
18 | 19 | from pynamodb import attributes |
|
24 | 25 | NumberAttribute, |
25 | 26 | ListAttribute, |
26 | 27 | JSONAttribute, |
27 | | - MapAttribute, DESERIALIZE_CLASS_MAP, |
| 28 | + MapAttribute, |
28 | 29 | ) |
29 | 30 | from pynamodb.expressions.condition import Condition |
30 | 31 | from pynamodb.indexes import GlobalSecondaryIndex, AllProjection |
@@ -708,14 +709,24 @@ class Meta: |
708 | 709 | company_id = UnicodeAttribute(hash_key=True) |
709 | 710 | project_id = UnicodeAttribute(range_key=True) |
710 | 711 |
|
| 712 | +class DateTimeAttribute(UTCDateTimeAttribute): |
| 713 | + """ |
| 714 | + We need to patch deserialize, see https://pynamodb.readthedocs.io/en/stable/upgrading.html#no-longer-parsing-date-time-strings-leniently |
| 715 | + This fails for ProjectModel.date_created having '2022-11-21T10:31:31Z' instead of strictly expected '2022-08-25T16:26:04.000000+0000' |
| 716 | + """ |
| 717 | + def deserialize(self, value): |
| 718 | + try: |
| 719 | + return self._fast_parse_utc_date_string(value) |
| 720 | + except (TypeError, ValueError): |
| 721 | + return parsedatestring(value) |
711 | 722 |
|
712 | 723 | class BaseModel(Model): |
713 | 724 | """ |
714 | 725 | Base pynamodb model used for all CLA models. |
715 | 726 | """ |
716 | 727 |
|
717 | | - date_created = UTCDateTimeAttribute(default=datetime.datetime.utcnow()) |
718 | | - date_modified = UTCDateTimeAttribute(default=datetime.datetime.utcnow()) |
| 728 | + date_created = DateTimeAttribute(default=datetime.datetime.utcnow()) |
| 729 | + date_modified = DateTimeAttribute(default=datetime.datetime.utcnow()) |
719 | 730 | version = UnicodeAttribute(default="v1") # Schema version. |
720 | 731 |
|
721 | 732 | def __iter__(self): |
@@ -934,8 +945,7 @@ class DocumentModel(MapAttribute): |
934 | 945 | document_major_version = NumberAttribute(default=1) |
935 | 946 | document_minor_version = NumberAttribute(default=0) |
936 | 947 | document_author_name = UnicodeAttribute() |
937 | | - # Not using UTCDateTimeAttribute due to https://github.com/pynamodb/PynamoDB/issues/162 |
938 | | - document_creation_date = UnicodeAttribute() |
| 948 | + document_creation_date = DateTimeAttribute() |
939 | 949 | document_preamble = UnicodeAttribute(null=True) |
940 | 950 | document_legal_entity_name = UnicodeAttribute(null=True) |
941 | 951 | document_s3_url = UnicodeAttribute(null=True) |
@@ -2573,10 +2583,6 @@ def __init__( |
2573 | 2583 | ): |
2574 | 2584 | super(Signature).__init__() |
2575 | 2585 |
|
2576 | | - # Patch the deserialize function of the ListAttribute - this addresses the issue when the List is 'None' |
2577 | | - # See notes below in the patched function which describes the problem in more details |
2578 | | - attributes.ListAttribute.deserialize = patched_deserialize |
2579 | | - |
2580 | 2586 | self.model = SignatureModel() |
2581 | 2587 | self.model.signature_id = signature_id |
2582 | 2588 | self.model.signature_external_id = signature_external_id |
@@ -3512,10 +3518,6 @@ def __init__( |
3512 | 3518 | ): |
3513 | 3519 | super(Company).__init__() |
3514 | 3520 |
|
3515 | | - # Patch the deserialize function of the ListAttribute - this addresses the issue when the List is 'None' |
3516 | | - # See notes below in the patched function which describes the problem in more details |
3517 | | - attributes.ListAttribute.deserialize = patched_deserialize |
3518 | | - |
3519 | 3521 | self.model = CompanyModel() |
3520 | 3522 | self.model.company_id = company_id |
3521 | 3523 | self.model.company_external_id = company_external_id |
@@ -4725,7 +4727,7 @@ class Meta: |
4725 | 4727 | event_user_name = UnicodeAttribute(null=True) |
4726 | 4728 | event_user_name_lower = UnicodeAttribute(null=True) |
4727 | 4729 |
|
4728 | | - event_time = UTCDateTimeAttribute(default=datetime.datetime.utcnow()) |
| 4730 | + event_time = DateTimeAttribute(default=datetime.datetime.utcnow()) |
4729 | 4731 | event_time_epoch = NumberAttribute(default=int(time.time())) |
4730 | 4732 | event_date = UnicodeAttribute(null=True) |
4731 | 4733 |
|
@@ -5417,34 +5419,3 @@ def all(self): |
5417 | 5419 | ccla_whitelist_request.model = request |
5418 | 5420 | ret.append(ccla_whitelist_request) |
5419 | 5421 | return ret |
5420 | | - |
5421 | | - |
5422 | | -def patched_deserialize(self, values): |
5423 | | - """ |
5424 | | - Decode from list of AttributeValue types. This is a patched version of the pynamodb version 3.4.1 which address |
5425 | | - the use-case where it attempts to iterate over a NoneType value. This is a known issue in pynamodb and has been |
5426 | | - resolved in the latest 5.x series of pynamodb. However, if we upgrade to this version it will break all the |
5427 | | - date/time processing in our models. So, we simply patch this version of the library to address this issue. |
5428 | | - """ |
5429 | | - deserialized_lst = [] |
5430 | | - if not values: |
5431 | | - return deserialized_lst |
5432 | | - for v in values: |
5433 | | - class_for_deserialize = self.element_type() if self.element_type else _get_class_for_deserialize(v) |
5434 | | - attr_value = _get_value_for_deserialize(v) |
5435 | | - deserialized_lst.append(class_for_deserialize.deserialize(attr_value)) |
5436 | | - return deserialized_lst |
5437 | | - |
5438 | | - |
5439 | | -def _get_value_for_deserialize(value): |
5440 | | - key = next(iter(value.keys())) |
5441 | | - if key == 'NULL': |
5442 | | - return None |
5443 | | - return value[key] |
5444 | | - |
5445 | | - |
5446 | | -def _get_class_for_deserialize(value): |
5447 | | - value_type = list(value.keys())[0] |
5448 | | - if value_type not in DESERIALIZE_CLASS_MAP: |
5449 | | - raise ValueError('Unknown value: ' + str(value)) |
5450 | | - return DESERIALIZE_CLASS_MAP[value_type] |
0 commit comments