You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by mi...@apache.org on 2023/08/04 17:13:39 UTC

[superset] 06/16: fix: Python3.11 (str, Enum) issue (#24803)

This is an automated email from the ASF dual-hosted git repository.

michaelsmolina pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 161e05445c2c02853be50c18d00fa22c3ceddeb4
Author: EugeneTorap <ev...@gmail.com>
AuthorDate: Mon Jul 31 19:04:09 2023 +0300

    fix: Python3.11 (str, Enum) issue (#24803)
---
 .pylintrc                                          |  1 +
 superset/common/chart_data.py                      |  6 ++---
 superset/common/db_query_status.py                 |  4 +--
 superset/connectors/base/models.py                 |  4 +--
 superset/constants.py                              |  8 +++---
 superset/errors.py                                 |  7 +++---
 superset/key_value/types.py                        |  6 ++---
 superset/models/core.py                            |  6 ++---
 superset/reports/models.py                         | 17 ++++++-------
 superset/sql_parse.py                              |  6 ++---
 superset/sqllab/limiting_factor.py                 |  4 +--
 superset/tasks/types.py                            |  5 ++--
 .../limiting_factor.py => utils/backports.py}      | 15 +++++------
 superset/utils/core.py                             | 29 +++++++++++-----------
 tests/unit_tests/utils/test_decorators.py          |  4 +--
 15 files changed, 63 insertions(+), 59 deletions(-)

diff --git a/.pylintrc b/.pylintrc
index b39335c56b..08e44d3fae 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -83,6 +83,7 @@ enable=
 # no Warning level messages displayed, use"--disable=all --enable=classes
 # --disable=W"
 disable=
+    no-member,  # re-enable once this no longer raises false positives. This will become redundant after the min required version is 3.11
     missing-docstring,
     duplicate-code,
     unspecified-encoding,
diff --git a/superset/common/chart_data.py b/superset/common/chart_data.py
index 65c0c43c11..e03f51eee2 100644
--- a/superset/common/chart_data.py
+++ b/superset/common/chart_data.py
@@ -14,10 +14,10 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-from enum import Enum
+from superset.utils.backports import StrEnum
 
 
-class ChartDataResultFormat(str, Enum):
+class ChartDataResultFormat(StrEnum):
     """
     Chart data response format
     """
@@ -31,7 +31,7 @@ class ChartDataResultFormat(str, Enum):
         return {cls.CSV} | {cls.XLSX}
 
 
-class ChartDataResultType(str, Enum):
+class ChartDataResultType(StrEnum):
     """
     Chart data response type
     """
diff --git a/superset/common/db_query_status.py b/superset/common/db_query_status.py
index 82bb437f65..fa893a1717 100644
--- a/superset/common/db_query_status.py
+++ b/superset/common/db_query_status.py
@@ -14,10 +14,10 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-from enum import Enum
+from superset.utils.backports import StrEnum
 
 
-class QueryStatus(str, Enum):
+class QueryStatus(StrEnum):
     """Enum-type class for query statuses"""
 
     STOPPED: str = "stopped"
diff --git a/superset/connectors/base/models.py b/superset/connectors/base/models.py
index 56e5ef18ad..706c82635c 100644
--- a/superset/connectors/base/models.py
+++ b/superset/connectors/base/models.py
@@ -21,7 +21,6 @@ import json
 import logging
 from collections.abc import Hashable
 from datetime import datetime
-from enum import Enum
 from json.decoder import JSONDecodeError
 from typing import Any, TYPE_CHECKING
 
@@ -44,6 +43,7 @@ from superset.superset_typing import (
     ResultSetColumnType,
 )
 from superset.utils import core as utils
+from superset.utils.backports import StrEnum
 from superset.utils.core import GenericDataType, MediumText
 
 if TYPE_CHECKING:
@@ -75,7 +75,7 @@ COLUMN_FORM_DATA_PARAMS = [
 ]
 
 
-class DatasourceKind(str, Enum):
+class DatasourceKind(StrEnum):
     VIRTUAL = "virtual"
     PHYSICAL = "physical"
 
diff --git a/superset/constants.py b/superset/constants.py
index 48b08506ca..4f01674bd4 100644
--- a/superset/constants.py
+++ b/superset/constants.py
@@ -20,6 +20,8 @@
 # string to use when None values *need* to be converted to/from strings
 from enum import Enum
 
+from superset.utils.backports import StrEnum
+
 USER_AGENT = "Apache Superset"
 
 NULL_STRING = "<NULL>"
@@ -185,7 +187,7 @@ EXTRA_FORM_DATA_OVERRIDE_KEYS = (
 )
 
 
-class TimeGrain(str, Enum):
+class TimeGrain(StrEnum):
     SECOND = "PT1S"
     FIVE_SECONDS = "PT5S"
     THIRTY_SECONDS = "PT30S"
@@ -214,13 +216,13 @@ class PandasAxis(int, Enum):
     COLUMN = 1
 
 
-class PandasPostprocessingCompare(str, Enum):
+class PandasPostprocessingCompare(StrEnum):
     DIFF = "difference"
     PCT = "percentage"
     RAT = "ratio"
 
 
-class CacheRegion(str, Enum):
+class CacheRegion(StrEnum):
     DEFAULT = "default"
     DATA = "data"
     THUMBNAIL = "thumbnail"
diff --git a/superset/errors.py b/superset/errors.py
index 6f68f2466c..6661e98183 100644
--- a/superset/errors.py
+++ b/superset/errors.py
@@ -15,13 +15,14 @@
 # specific language governing permissions and limitations
 # under the License.
 from dataclasses import dataclass
-from enum import Enum
 from typing import Any, Optional
 
 from flask_babel import lazy_gettext as _
 
+from superset.utils.backports import StrEnum
 
-class SupersetErrorType(str, Enum):
+
+class SupersetErrorType(StrEnum):
     """
     Types of errors that can exist within Superset.
 
@@ -183,7 +184,7 @@ ERROR_TYPES_TO_ISSUE_CODES_MAPPING = {
 }
 
 
-class ErrorLevel(str, Enum):
+class ErrorLevel(StrEnum):
     """
     Levels of errors that can exist within Superset.
 
diff --git a/superset/key_value/types.py b/superset/key_value/types.py
index b2a47336c3..f5865de323 100644
--- a/superset/key_value/types.py
+++ b/superset/key_value/types.py
@@ -20,7 +20,6 @@ import json
 import pickle
 from abc import ABC, abstractmethod
 from dataclasses import dataclass
-from enum import Enum
 from typing import Any, TypedDict
 from uuid import UUID
 
@@ -30,6 +29,7 @@ from superset.key_value.exceptions import (
     KeyValueCodecDecodeException,
     KeyValueCodecEncodeException,
 )
+from superset.utils.backports import StrEnum
 
 
 @dataclass
@@ -44,14 +44,14 @@ class KeyValueFilter(TypedDict, total=False):
     uuid: UUID | None
 
 
-class KeyValueResource(str, Enum):
+class KeyValueResource(StrEnum):
     APP = "app"
     DASHBOARD_PERMALINK = "dashboard_permalink"
     EXPLORE_PERMALINK = "explore_permalink"
     METASTORE_CACHE = "superset_metastore_cache"
 
 
-class SharedKey(str, Enum):
+class SharedKey(StrEnum):
     DASHBOARD_PERMALINK_SALT = "dashboard_permalink_salt"
     EXPLORE_PERMALINK_SALT = "explore_permalink_salt"
 
diff --git a/superset/models/core.py b/superset/models/core.py
index a8fe8b5411..21f8eddba4 100755
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -20,7 +20,6 @@
 from __future__ import annotations
 
 import builtins
-import enum
 import json
 import logging
 import textwrap
@@ -74,6 +73,7 @@ from superset.models.helpers import AuditMixinNullable, ImportExportMixin
 from superset.result_set import SupersetResultSet
 from superset.superset_typing import ResultSetColumnType
 from superset.utils import cache as cache_util, core as utils
+from superset.utils.backports import StrEnum
 from superset.utils.core import get_username
 
 config = app.config
@@ -116,7 +116,7 @@ class CssTemplate(Model, AuditMixinNullable):
     css = Column(Text, default="")
 
 
-class ConfigurationMethod(str, enum.Enum):
+class ConfigurationMethod(StrEnum):
     SQLALCHEMY_FORM = "sqlalchemy_form"
     DYNAMIC_FORM = "dynamic_form"
 
@@ -1007,7 +1007,7 @@ class Log(Model):  # pylint: disable=too-few-public-methods
     referrer = Column(String(1024))
 
 
-class FavStarClassName(str, enum.Enum):
+class FavStarClassName(StrEnum):
     CHART = "slice"
     DASHBOARD = "Dashboard"
 
diff --git a/superset/reports/models.py b/superset/reports/models.py
index a13ded6223..5c47f41456 100644
--- a/superset/reports/models.py
+++ b/superset/reports/models.py
@@ -15,8 +15,6 @@
 # specific language governing permissions and limitations
 # under the License.
 """A collection of ORM sqlalchemy models for Superset"""
-import enum
-
 from cron_descriptor import get_description
 from flask_appbuilder import Model
 from flask_appbuilder.models.decorators import renders
@@ -41,28 +39,29 @@ from superset.models.dashboard import Dashboard
 from superset.models.helpers import AuditMixinNullable, ExtraJSONMixin
 from superset.models.slice import Slice
 from superset.reports.types import ReportScheduleExtra
+from superset.utils.backports import StrEnum
 
 metadata = Model.metadata  # pylint: disable=no-member
 
 
-class ReportScheduleType(str, enum.Enum):
+class ReportScheduleType(StrEnum):
     ALERT = "Alert"
     REPORT = "Report"
 
 
-class ReportScheduleValidatorType(str, enum.Enum):
+class ReportScheduleValidatorType(StrEnum):
     """Validator types for alerts"""
 
     NOT_NULL = "not null"
     OPERATOR = "operator"
 
 
-class ReportRecipientType(str, enum.Enum):
+class ReportRecipientType(StrEnum):
     EMAIL = "Email"
     SLACK = "Slack"
 
 
-class ReportState(str, enum.Enum):
+class ReportState(StrEnum):
     SUCCESS = "Success"
     WORKING = "Working"
     ERROR = "Error"
@@ -70,19 +69,19 @@ class ReportState(str, enum.Enum):
     GRACE = "On Grace"
 
 
-class ReportDataFormat(str, enum.Enum):
+class ReportDataFormat(StrEnum):
     VISUALIZATION = "PNG"
     DATA = "CSV"
     TEXT = "TEXT"
 
 
-class ReportCreationMethod(str, enum.Enum):
+class ReportCreationMethod(StrEnum):
     CHARTS = "charts"
     DASHBOARDS = "dashboards"
     ALERTS_REPORTS = "alerts_reports"
 
 
-class ReportSourceFormat(str, enum.Enum):
+class ReportSourceFormat(StrEnum):
     CHART = "chart"
     DASHBOARD = "dashboard"
 
diff --git a/superset/sql_parse.py b/superset/sql_parse.py
index 974d7eacd4..a6d4806707 100644
--- a/superset/sql_parse.py
+++ b/superset/sql_parse.py
@@ -18,7 +18,6 @@ import logging
 import re
 from collections.abc import Iterator
 from dataclasses import dataclass
-from enum import Enum
 from typing import Any, cast, Optional
 from urllib import parse
 
@@ -49,6 +48,7 @@ from sqlparse.tokens import (
 from sqlparse.utils import imt
 
 from superset.exceptions import QueryClauseValidationException
+from superset.utils.backports import StrEnum
 
 try:
     from sqloxide import parse_sql as sqloxide_parse
@@ -71,7 +71,7 @@ sqlparser_sql_regex.insert(25, (r"'(''|\\\\|\\|[^'])*'", sqlparse.tokens.String.
 lex.set_SQL_REGEX(sqlparser_sql_regex)
 
 
-class CtasMethod(str, Enum):
+class CtasMethod(StrEnum):
     TABLE = "TABLE"
     VIEW = "VIEW"
 
@@ -483,7 +483,7 @@ def sanitize_clause(clause: str) -> str:
     return clause
 
 
-class InsertRLSState(str, Enum):
+class InsertRLSState(StrEnum):
     """
     State machine that scans for WHERE and ON clauses referencing tables.
     """
diff --git a/superset/sqllab/limiting_factor.py b/superset/sqllab/limiting_factor.py
index 46cbc9bd81..638f9e347a 100644
--- a/superset/sqllab/limiting_factor.py
+++ b/superset/sqllab/limiting_factor.py
@@ -14,10 +14,10 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-import enum
+from superset.utils.backports import StrEnum
 
 
-class LimitingFactor(str, enum.Enum):
+class LimitingFactor(StrEnum):
     QUERY = "QUERY"
     DROPDOWN = "DROPDOWN"
     QUERY_AND_DROPDOWN = "QUERY_AND_DROPDOWN"
diff --git a/superset/tasks/types.py b/superset/tasks/types.py
index cc337a81ed..84a3e7b01f 100644
--- a/superset/tasks/types.py
+++ b/superset/tasks/types.py
@@ -14,11 +14,10 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+from superset.utils.backports import StrEnum
 
-from enum import Enum
 
-
-class ExecutorType(str, Enum):
+class ExecutorType(StrEnum):
     """
     Which user should scheduled tasks be executed as. Used as follows:
     For Alerts & Reports: the "model" refers to the AlertSchedule object
diff --git a/superset/sqllab/limiting_factor.py b/superset/utils/backports.py
similarity index 79%
copy from superset/sqllab/limiting_factor.py
copy to superset/utils/backports.py
index 46cbc9bd81..b48f76d235 100644
--- a/superset/sqllab/limiting_factor.py
+++ b/superset/utils/backports.py
@@ -14,12 +14,13 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-import enum
+import sys
+from enum import Enum
 
+if sys.version_info >= (3, 11):
+    # pylint: disable=unused-import
+    from enum import StrEnum  # nopycln: import
+else:
 
-class LimitingFactor(str, enum.Enum):
-    QUERY = "QUERY"
-    DROPDOWN = "DROPDOWN"
-    QUERY_AND_DROPDOWN = "QUERY_AND_DROPDOWN"
-    NOT_LIMITED = "NOT_LIMITED"
-    UNKNOWN = "UNKNOWN"
+    class StrEnum(str, Enum):
+        pass
diff --git a/superset/utils/core.py b/superset/utils/core.py
index ca3b9ae7b7..f40ccb63a2 100644
--- a/superset/utils/core.py
+++ b/superset/utils/core.py
@@ -98,6 +98,7 @@ from superset.superset_typing import (
     FormData,
     Metric,
 )
+from superset.utils.backports import StrEnum
 from superset.utils.database import get_example_database
 from superset.utils.date_parser import parse_human_timedelta
 from superset.utils.dates import datetime_to_epoch, EPOCH
@@ -133,12 +134,12 @@ class LenientEnum(Enum):
             return None
 
 
-class AdhocMetricExpressionType(str, Enum):
+class AdhocMetricExpressionType(StrEnum):
     SIMPLE = "SIMPLE"
     SQL = "SQL"
 
 
-class AnnotationType(str, Enum):
+class AnnotationType(StrEnum):
     FORMULA = "FORMULA"
     INTERVAL = "INTERVAL"
     EVENT = "EVENT"
@@ -160,7 +161,7 @@ class GenericDataType(IntEnum):
     # ROW = 7
 
 
-class DatasourceType(str, Enum):
+class DatasourceType(StrEnum):
     SLTABLE = "sl_table"
     TABLE = "table"
     DATASET = "dataset"
@@ -169,7 +170,7 @@ class DatasourceType(str, Enum):
     VIEW = "view"
 
 
-class LoggerLevel(str, Enum):
+class LoggerLevel(StrEnum):
     INFO = "info"
     WARNING = "warning"
     EXCEPTION = "exception"
@@ -208,19 +209,19 @@ class QueryObjectFilterClause(TypedDict, total=False):
     isExtra: bool | None
 
 
-class ExtraFiltersTimeColumnType(str, Enum):
+class ExtraFiltersTimeColumnType(StrEnum):
     TIME_COL = "__time_col"
     TIME_GRAIN = "__time_grain"
     TIME_ORIGIN = "__time_origin"
     TIME_RANGE = "__time_range"
 
 
-class ExtraFiltersReasonType(str, Enum):
+class ExtraFiltersReasonType(StrEnum):
     NO_TEMPORAL_COLUMN = "no_temporal_column"
     COL_NOT_IN_DATASOURCE = "not_in_datasource"
 
 
-class FilterOperator(str, Enum):
+class FilterOperator(StrEnum):
     """
     Operators used filter controls
     """
@@ -242,7 +243,7 @@ class FilterOperator(str, Enum):
     TEMPORAL_RANGE = "TEMPORAL_RANGE"
 
 
-class FilterStringOperators(str, Enum):
+class FilterStringOperators(StrEnum):
     EQUALS = ("EQUALS",)
     NOT_EQUALS = ("NOT_EQUALS",)
     LESS_THAN = ("LESS_THAN",)
@@ -260,7 +261,7 @@ class FilterStringOperators(str, Enum):
     IS_FALSE = ("IS_FALSE",)
 
 
-class PostProcessingBoxplotWhiskerType(str, Enum):
+class PostProcessingBoxplotWhiskerType(StrEnum):
     """
     Calculate cell contribution to row/column total
     """
@@ -270,7 +271,7 @@ class PostProcessingBoxplotWhiskerType(str, Enum):
     PERCENTILE = "percentile"
 
 
-class PostProcessingContributionOrientation(str, Enum):
+class PostProcessingContributionOrientation(StrEnum):
     """
     Calculate cell contribution to row/column total
     """
@@ -298,7 +299,7 @@ class QuerySource(Enum):
     SQL_LAB = 2
 
 
-class QueryStatus(str, Enum):
+class QueryStatus(StrEnum):
     """Enum-type class for query statuses"""
 
     STOPPED: str = "stopped"
@@ -311,14 +312,14 @@ class QueryStatus(str, Enum):
     TIMED_OUT: str = "timed_out"
 
 
-class DashboardStatus(str, Enum):
+class DashboardStatus(StrEnum):
     """Dashboard status used for frontend filters"""
 
     PUBLISHED = "published"
     DRAFT = "draft"
 
 
-class ReservedUrlParameters(str, Enum):
+class ReservedUrlParameters(StrEnum):
     """
     Reserved URL parameters that are used internally by Superset. These will not be
     passed to chart queries, as they control the behavior of the UI.
@@ -336,7 +337,7 @@ class ReservedUrlParameters(str, Enum):
         return standalone
 
 
-class RowLevelSecurityFilterType(str, Enum):
+class RowLevelSecurityFilterType(StrEnum):
     REGULAR = "Regular"
     BASE = "Base"
 
diff --git a/tests/unit_tests/utils/test_decorators.py b/tests/unit_tests/utils/test_decorators.py
index 3aafc7a91d..f600334414 100644
--- a/tests/unit_tests/utils/test_decorators.py
+++ b/tests/unit_tests/utils/test_decorators.py
@@ -17,7 +17,6 @@
 
 
 from contextlib import nullcontext
-from enum import Enum
 from inspect import isclass
 from typing import Any, Optional
 from unittest.mock import call, Mock, patch
@@ -26,9 +25,10 @@ import pytest
 
 from superset import app
 from superset.utils import decorators
+from superset.utils.backports import StrEnum
 
 
-class ResponseValues(str, Enum):
+class ResponseValues(StrEnum):
     FAIL = "fail"
     WARN = "warn"
     OK = "ok"