class_docstr: The query context contains the query object and additional fields necessary
  to retrieve the data payload for a given viz.
class_docstr_tok: ["The","query","context","contains","the","query","object","and","additional","fields","necessary","to","retrieve","the","data","payload","for","a","given","viz","."]
code: def normalize_df(
      self, df: pd.DataFrame, query_object: QueryObject
  ) -> pd.DataFrame:
      # todo: should support "python_date_format" and "get_column" in each datasource
      def _get_timestamp_format(
          source: BaseDatasource, column: str | None
      ) -> str | None:
          column_obj = source.get_column(column)
          if (
              column_obj
              # only sqla column was supported
              and hasattr(column_obj, "python_date_format")
              and (formatter := column_obj.python_date_format)
          ):
              return str(formatter)
  
          return None
  
      datasource = self._qc_datasource
      labels = tuple(
          label
          for label in [
              *get_base_axis_labels(query_object.columns),
              query_object.granularity,
          ]
          if datasource
          # Query datasource didn't support `get_column`
          and hasattr(datasource, "get_column")
          and (col := datasource.get_column(label))
          # todo(hugh) standardize column object in Query datasource
          and (
              col.get("is_dttm")
              if isinstance(col, dict)
              else col.is_dttm
          )
      )
      dttm_cols = [
          DateColumn(
              timestamp_format=_get_timestamp_format(datasource, label),
              offset=datasource.offset,
              time_shift=query_object.time_shift,
              col_label=label,
          )
          for label in labels
          if label
      ]
      if DTTM_ALIAS in df:
          dttm_cols.append(
              DateColumn.get_legacy_time_column(
                  timestamp_format=_get_timestamp_format(
                      datasource, query_object.granularity
                  ),
                  offset=datasource.offset,
                  time_shift=query_object.time_shift,
              )
          )
      normalize_dttm_col(
          df=df,
          dttm_cols=tuple(dttm_cols),
      )
  
      if self.enforce_numerical_metrics:
          dataframe_utils.df_metrics_to_num(df, query_object)
  
      df.replace([np.inf, -np.inf], np.nan, inplace=True)
  
      return df
  
imports: from __future__ import annotations
  import copy
  import logging
  import re
  from typing import Any, ClassVar, TYPE_CHECKING, TypedDict
  import numpy
  import pandas
  from flask_babel import gettext
  from pandas import DateOffset
  from superset import app
  from superset.common.chart_data import ChartDataResultFormat
  from superset.common.db_query_status import QueryStatus
  from superset.common.query_actions import get_query_results
  from superset.common.utils import dataframe_utils
  from superset.common.utils.query_cache_manager import QueryCacheManager
  from superset.common.utils.time_range_utils import get_since_until_from_query_object, get_since_until_from_time_range
  from superset.connectors.sqla.models import BaseDatasource
  from superset.constants import CacheRegion, TimeGrain
  from superset.daos.annotation_layer import AnnotationLayerDAO
  from superset.daos.chart import ChartDAO
  from superset.exceptions import InvalidPostProcessingError, QueryObjectValidationError, SupersetException
  from superset.extensions import cache_manager, security_manager
  from superset.models.helpers import QueryResult
  from superset.models.sql_lab import Query
  from superset.utils import csv, excel
  from superset.utils.cache import generate_cache_key, set_and_log_cache
  from superset.utils.core import DatasourceType, DateColumn, DTTM_ALIAS, error_msg_from_exception, get_base_axis_labels, get_column_names_from_columns, get_column_names_from_metrics, get_metric_names, get_xaxis_label, normalize_dttm_col, TIME_COMPARISON
  from superset.utils.date_parser import get_past_or_future, normalize_time_delta
  from superset.utils.pandas_postprocessing.utils import unescape_separator
  from superset.views.utils import get_viz
  from superset.viz import viz_types
label_desc: Use image node_id 5 for calling the QueryContextProcessor obj's underlying member method code with example usage: obj.normalize_df(df, query_object) and returns: df, None, str