From 719ddff23819133710797f5d01acaf9b38cbd481 Mon Sep 17 00:00:00 2001 From: Leangseu Kim Date: Thu, 11 Aug 2022 11:01:41 -0400 Subject: [PATCH] fix: section.due datetime version issue --- lms/djangoapps/grades/subsection_grade.py | 2 +- .../block_structure/block_structure.py | 26 ++--------------- xmodule/block_metadata_utils.py | 29 +++++++++++++++++++ 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/lms/djangoapps/grades/subsection_grade.py b/lms/djangoapps/grades/subsection_grade.py index 2b777345ea..ba098a92a4 100644 --- a/lms/djangoapps/grades/subsection_grade.py +++ b/lms/djangoapps/grades/subsection_grade.py @@ -27,7 +27,7 @@ class SubsectionGradeBase(metaclass=ABCMeta): self.display_name = block_metadata_utils.display_name_with_default(subsection) self.url_name = block_metadata_utils.url_name_for_block(subsection) - self.due = getattr(subsection, 'due', None) + self.due = block_metadata_utils.get_datetime_field(subsection, 'due', None) self.end = getattr(subsection, 'end', None) self.format = getattr(subsection, 'format', '') self.graded = getattr(subsection, 'graded', False) diff --git a/openedx/core/djangoapps/content/block_structure/block_structure.py b/openedx/core/djangoapps/content/block_structure/block_structure.py index ba9990bb79..d7ef27fcce 100644 --- a/openedx/core/djangoapps/content/block_structure/block_structure.py +++ b/openedx/core/djangoapps/content/block_structure/block_structure.py @@ -11,11 +11,10 @@ The following internal data structures are implemented: from copy import deepcopy -from datetime import datetime from functools import partial from logging import getLogger -from dateutil.tz import tzlocal +from xmodule.block_metadata_utils import get_datetime_field from openedx.core.lib.graph_traversals import traverse_post_order, traverse_topologically @@ -467,8 +466,7 @@ class BlockStructureBlockData(BlockStructure): not found. """ block_data = self._block_data_map.get(usage_key) - xblock_field = getattr(block_data, field_name, default) if block_data else default - return self._make_datetime_field_compatible(xblock_field) + return get_datetime_field(block_data, field_name, default) if block_data else default def override_xblock_field(self, usage_key, field_name, override_data): """ @@ -558,8 +556,7 @@ class BlockStructureBlockData(BlockStructure): transformer_data = self.get_transformer_block_data(usage_key, transformer) except KeyError: return default - field = getattr(transformer_data, key, default) - return self._make_datetime_field_compatible(field) + return get_datetime_field(transformer_data, key, default) def set_transformer_block_field(self, usage_key, transformer, key, value): """ @@ -768,23 +765,6 @@ class BlockStructureBlockData(BlockStructure): self._block_data_map[usage_key] = block_data return block_data - def _make_datetime_field_compatible(self, field): - """ - Creates a new datetime object to avoid issues occurring due to upgrading - python-datetuil version from 2.4.0 - - More info: https://openedx.atlassian.net/browse/BOM-2245 - """ - if isinstance(field, datetime): - if isinstance(field.tzinfo, tzlocal) and not hasattr(field.tzinfo, '_hasdst'): - - return datetime( - year=field.year, month=field.month, day=field.day, - hour=field.hour, minute=field.minute, second=field.second, - tzinfo=tzlocal() - ) - return field - class BlockStructureModulestoreData(BlockStructureBlockData): """ diff --git a/xmodule/block_metadata_utils.py b/xmodule/block_metadata_utils.py index e29b70ffdc..1015c0e009 100644 --- a/xmodule/block_metadata_utils.py +++ b/xmodule/block_metadata_utils.py @@ -6,8 +6,14 @@ allows us to share code between the XModuleMixin and CourseOverview and BlockStructure. """ +from datetime import datetime +from logging import getLogger from markupsafe import Markup +from dateutil.tz import tzlocal + +logger = getLogger(__name__) # pylint: disable=invalid-name + def url_name_for_block(block): """ @@ -80,3 +86,26 @@ def display_name_with_default_escaped(block): # markupsafe.striptags() and fixing issues, better to put that energy toward # migrating away from this method altogether. return Markup(display_name_with_default(block)).striptags() + + +def get_datetime_field(xblock, name, default): + """ + This method was moved from BlockStructureBlockData because some of the datetime + that was cached from previous version of dateutil does not live here. This will + be use as share code for reusability and Wack-a-mole situation of the same bug. + + Creates a new datetime object to avoid issues occurring due to upgrading + python-datetuil version from 2.4.0 + More info: https://openedx.atlassian.net/browse/BOM-2245 + """ + field = getattr(xblock, name, default) + if isinstance(field, datetime): + if isinstance(field.tzinfo, tzlocal) and not hasattr(field.tzinfo, '_hasdst'): + # Todo: This log statement is added for temporary use only + logger.info('Python-dateutil logs: Making datetime field compatible to python-dateutil package') + return datetime( + year=field.year, month=field.month, day=field.day, + hour=field.hour, minute=field.minute, second=field.second, + tzinfo=tzlocal() + ) + return field