From 355e462adba14cfef2596934b5f271103a3ebc41 Mon Sep 17 00:00:00 2001 From: Farhan Anjum Date: Fri, 16 Oct 2026 21:14:58 +0600 Subject: [PATCH 1/2] [FSSDK-13300] Remove dead Python 3.7 typing guards and pin mypy mypy 2.4.0 rejects the `if version_info < (3, 8)` conditional Protocol imports, failing type-check on every PR. Those branches only run on Python 3.7, which has been unsupported since 5.0, so import Final, Literal, Protocol and TypedDict directly from typing. Drop the mypy.ini unused-ignore override that existed only for the old TypedDict import, and pin mypy~=2.4.0 so new mypy releases can't break CI unannounced. Co-Authored-By: Claude Opus 5.5 --- mypy.ini | 4 ---- optimizely/bucketer.py | 9 +-------- optimizely/decision/optimizely_decide_option.py | 7 +------ .../decision/optimizely_decision_message.py | 7 +------ optimizely/entities.py | 8 +------- optimizely/event/event_factory.py | 8 +------- optimizely/event/event_processor.py | 9 +-------- optimizely/event/log_event.py | 9 +-------- optimizely/event/user_event.py | 9 +-------- optimizely/event_builder.py | 8 +------- optimizely/event_dispatcher.py | 7 +------ optimizely/helpers/condition.py | 9 +-------- optimizely/helpers/enums.py | 7 +------ optimizely/helpers/event_tag_utils.py | 8 +------- optimizely/helpers/types.py | 9 +-------- optimizely/logger.py | 8 +------- optimizely/notification_center.py | 8 +------- optimizely/odp/lru_cache.py | 8 +------- optimizely/odp/optimizely_odp_option.py | 7 +------ optimizely/project_config.py | 8 +------- optimizely/user_profile.py | 16 +++++----------- requirements/typing.txt | 2 +- 22 files changed, 25 insertions(+), 150 deletions(-) diff --git a/mypy.ini b/mypy.ini index 5de83593c..8d7ecd550 100644 --- a/mypy.ini +++ b/mypy.ini @@ -9,7 +9,3 @@ exclude = (?x)( ) show_error_codes = True pretty = True - -# suppress error on conditional import of typing_extensions module -[mypy-optimizely.helpers.types] -no_warn_unused_ignores = True diff --git a/optimizely/bucketer.py b/optimizely/bucketer.py index d1e0b047c..e21fb865e 100644 --- a/optimizely/bucketer.py +++ b/optimizely/bucketer.py @@ -12,19 +12,12 @@ # limitations under the License. from __future__ import annotations -from typing import Optional, TYPE_CHECKING, cast +from typing import Optional, TYPE_CHECKING, cast, Final import math -from sys import version_info from .lib import pymmh3 as mmh3 -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final - - if TYPE_CHECKING: # prevent circular dependenacy by skipping import at runtime from .project_config import ProjectConfig diff --git a/optimizely/decision/optimizely_decide_option.py b/optimizely/decision/optimizely_decide_option.py index 0443ddef4..7e5e43505 100644 --- a/optimizely/decision/optimizely_decide_option.py +++ b/optimizely/decision/optimizely_decide_option.py @@ -11,12 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final +from typing import Final class OptimizelyDecideOption: diff --git a/optimizely/decision/optimizely_decision_message.py b/optimizely/decision/optimizely_decision_message.py index c61783225..27112d8ff 100644 --- a/optimizely/decision/optimizely_decision_message.py +++ b/optimizely/decision/optimizely_decision_message.py @@ -11,12 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final +from typing import Final class OptimizelyDecisionMessage: diff --git a/optimizely/entities.py b/optimizely/entities.py index 39caafe67..b928141c2 100644 --- a/optimizely/entities.py +++ b/optimizely/entities.py @@ -11,13 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Any, Optional, Sequence -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final +from typing import TYPE_CHECKING, Any, Optional, Sequence, Final if TYPE_CHECKING: diff --git a/optimizely/event/event_factory.py b/optimizely/event/event_factory.py index b6a9c02ae..34bc04e2f 100644 --- a/optimizely/event/event_factory.py +++ b/optimizely/event/event_factory.py @@ -12,8 +12,7 @@ # limitations under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Optional, Sequence, cast, List -from sys import version_info +from typing import TYPE_CHECKING, Optional, Sequence, cast, List, Final from optimizely import entities from optimizely.helpers import enums from optimizely.helpers import event_tag_utils @@ -23,11 +22,6 @@ from . import payload from . import user_event -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final - if TYPE_CHECKING: # prevent circular dependenacy by skipping import at runtime from optimizely.project_config import ProjectConfig diff --git a/optimizely/event/event_processor.py b/optimizely/event/event_processor.py index bdce6d9da..0d0211d04 100644 --- a/optimizely/event/event_processor.py +++ b/optimizely/event/event_processor.py @@ -17,10 +17,9 @@ import threading import time -from typing import Optional +from typing import Optional, Final from datetime import timedelta import queue -from sys import version_info from optimizely import logger as _logging from optimizely import notification_center as _notification_center @@ -31,12 +30,6 @@ from .user_event import UserEvent -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final - - class BaseEventProcessor(ABC): """ Class encapsulating event processing. Override with your own implementation. """ diff --git a/optimizely/event/log_event.py b/optimizely/event/log_event.py index 49c344dd8..568c2cefd 100644 --- a/optimizely/event/log_event.py +++ b/optimizely/event/log_event.py @@ -12,17 +12,10 @@ # limitations under the License. from __future__ import annotations -from typing import Optional, Any -from sys import version_info +from typing import Optional, Any, Literal from optimizely import event_builder -if version_info < (3, 8): - from typing_extensions import Literal -else: - from typing import Literal - - class LogEvent(event_builder.Event): """ Representation of an event which can be sent to Optimizely events API. """ diff --git a/optimizely/event/user_event.py b/optimizely/event/user_event.py index 8006c052e..a2cb2df70 100644 --- a/optimizely/event/user_event.py +++ b/optimizely/event/user_event.py @@ -13,18 +13,11 @@ from __future__ import annotations import time import uuid -from typing import TYPE_CHECKING, Optional -from sys import version_info +from typing import TYPE_CHECKING, Optional, Final from optimizely import version -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final - - if TYPE_CHECKING: # prevent circular dependenacy by skipping import at runtime from optimizely.entities import Experiment, Variation, Event, Holdout diff --git a/optimizely/event_builder.py b/optimizely/event_builder.py index 7ef6b347a..67169d2a8 100644 --- a/optimizely/event_builder.py +++ b/optimizely/event_builder.py @@ -13,9 +13,8 @@ from __future__ import annotations import time -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any, Optional, Final, Literal import uuid -from sys import version_info from . import version from .event import event_id_normalizer @@ -23,11 +22,6 @@ from .helpers import event_tag_utils from .helpers import validator -if version_info < (3, 8): - from typing_extensions import Final, Literal -else: - from typing import Final, Literal - if TYPE_CHECKING: # prevent circular dependenacy by skipping import at runtime from .entities import Experiment diff --git a/optimizely/event_dispatcher.py b/optimizely/event_dispatcher.py index b06b9e187..cf4683401 100644 --- a/optimizely/event_dispatcher.py +++ b/optimizely/event_dispatcher.py @@ -13,7 +13,7 @@ import json import logging -from sys import version_info +from typing import Protocol import requests from requests import exceptions as request_exception @@ -23,11 +23,6 @@ from . import event_builder from .helpers.enums import HTTPVerbs, EventDispatchConfig -if version_info < (3, 8): - from typing_extensions import Protocol -else: - from typing import Protocol - class CustomEventDispatcher(Protocol): """Interface for a custom event dispatcher and required method `dispatch_event`. """ diff --git a/optimizely/helpers/condition.py b/optimizely/helpers/condition.py index 40338b407..48f097d99 100644 --- a/optimizely/helpers/condition.py +++ b/optimizely/helpers/condition.py @@ -14,8 +14,7 @@ from __future__ import annotations import json import numbers -from typing import TYPE_CHECKING, Any, Callable, Optional -from sys import version_info +from typing import TYPE_CHECKING, Any, Callable, Optional, Literal, Final from . import validator from optimizely import optimizely_user_context @@ -29,12 +28,6 @@ from optimizely.logger import Logger -if version_info < (3, 8): - from typing_extensions import Literal, Final -else: - from typing import Literal, Final - - class ConditionOperatorTypes: AND: Final = 'and' OR: Final = 'or' diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index 2d1d46764..0e4eb3168 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -12,12 +12,7 @@ # limitations under the License. import logging -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final +from typing import Final class CommonAudienceEvaluationLogs: diff --git a/optimizely/helpers/event_tag_utils.py b/optimizely/helpers/event_tag_utils.py index ad90cc132..618259508 100644 --- a/optimizely/helpers/event_tag_utils.py +++ b/optimizely/helpers/event_tag_utils.py @@ -12,16 +12,10 @@ # limitations under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Any, Optional, NewType, Dict +from typing import TYPE_CHECKING, Any, Optional, NewType, Dict, Final from . import enums import math import numbers -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final if TYPE_CHECKING: diff --git a/optimizely/helpers/types.py b/optimizely/helpers/types.py index 7b65ab134..2d8ba7d4f 100644 --- a/optimizely/helpers/types.py +++ b/optimizely/helpers/types.py @@ -12,14 +12,7 @@ # limitations under the License. from __future__ import annotations -from typing import Literal, Optional, Any -from sys import version_info - - -if version_info < (3, 8): - from typing_extensions import TypedDict -else: - from typing import TypedDict # type: ignore +from typing import Literal, Optional, Any, TypedDict # Intermediate types for type checking deserialized datafile json before actual class instantiation. diff --git a/optimizely/logger.py b/optimizely/logger.py index 42f879de6..c50b36940 100644 --- a/optimizely/logger.py +++ b/optimizely/logger.py @@ -11,17 +11,11 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging -from typing import Any, Optional, Union +from typing import Any, Optional, Union, Final import warnings -from sys import version_info from .helpers import enums -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final - _DEFAULT_LOG_FORMAT: Final = '%(levelname)-8s %(asctime)s %(filename)s:%(lineno)s:%(message)s' diff --git a/optimizely/notification_center.py b/optimizely/notification_center.py index 3d0b0cba3..b6b89ffda 100644 --- a/optimizely/notification_center.py +++ b/optimizely/notification_center.py @@ -12,15 +12,9 @@ # limitations under the License. from __future__ import annotations -from typing import Any, Callable, Optional +from typing import Any, Callable, Optional, Final from .helpers import enums from . import logger as optimizely_logger -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final NOTIFICATION_TYPES: Final = tuple( diff --git a/optimizely/odp/lru_cache.py b/optimizely/odp/lru_cache.py index 64337dadd..55d62a948 100644 --- a/optimizely/odp/lru_cache.py +++ b/optimizely/odp/lru_cache.py @@ -16,13 +16,7 @@ import threading from time import time from collections import OrderedDict -from typing import Optional, Generic, TypeVar, Hashable -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Protocol -else: - from typing import Protocol +from typing import Optional, Generic, TypeVar, Hashable, Protocol # generic type definitions for LRUCache parameters K = TypeVar('K', bound=Hashable, contravariant=True) diff --git a/optimizely/odp/optimizely_odp_option.py b/optimizely/odp/optimizely_odp_option.py index 94e1e90e4..62163fd76 100644 --- a/optimizely/odp/optimizely_odp_option.py +++ b/optimizely/odp/optimizely_odp_option.py @@ -11,12 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sys import version_info - -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final +from typing import Final class OptimizelyOdpOption: diff --git a/optimizely/project_config.py b/optimizely/project_config.py index a7152ae83..3cbf730e3 100644 --- a/optimizely/project_config.py +++ b/optimizely/project_config.py @@ -12,8 +12,7 @@ # limitations under the License. from __future__ import annotations import json -from typing import TYPE_CHECKING, Optional, Type, TypeVar, Union, cast, Any, Iterable, List -from sys import version_info +from typing import TYPE_CHECKING, Optional, Type, TypeVar, Union, cast, Any, Iterable, List, Final from . import entities from . import exceptions @@ -21,11 +20,6 @@ from .helpers import enums from .helpers import types -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final - if TYPE_CHECKING: # prevent circular dependenacy by skipping import at runtime from .logger import Logger diff --git a/optimizely/user_profile.py b/optimizely/user_profile.py index e3a56195c..591df5eac 100644 --- a/optimizely/user_profile.py +++ b/optimizely/user_profile.py @@ -12,19 +12,13 @@ # limitations under the License. from __future__ import annotations -from typing import Any, Optional -from sys import version_info +from typing import Any, Optional, Final, TYPE_CHECKING from . import logger as _logging -if version_info < (3, 8): - from typing_extensions import Final -else: - from typing import Final, TYPE_CHECKING - - if TYPE_CHECKING: - # prevent circular dependenacy by skipping import at runtime - from .entities import Experiment, Variation - from optimizely.error_handler import BaseErrorHandler +if TYPE_CHECKING: + # prevent circular dependenacy by skipping import at runtime + from .entities import Experiment, Variation + from optimizely.error_handler import BaseErrorHandler class UserProfile: diff --git a/requirements/typing.txt b/requirements/typing.txt index 4c01897b6..aad498b11 100644 --- a/requirements/typing.txt +++ b/requirements/typing.txt @@ -1,4 +1,4 @@ -mypy +mypy~=2.4.0 types-jsonschema types-requests types-Flask From a1548e1ebcbdd29a7508524aef48f89eefb1bdd3 Mon Sep 17 00:00:00 2001 From: Farhan Anjum Date: Fri, 16 Oct 2026 23:00:08 +0600 Subject: [PATCH 2/2] [FSSDK-13300] Leave mypy unpinned Keep requirements/typing.txt as on master. The typing import cleanup alone fixes the mypy 2.4.0 failure. Co-Authored-By: Claude Opus 5.5 --- requirements/typing.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/typing.txt b/requirements/typing.txt index aad498b11..4c01897b6 100644 --- a/requirements/typing.txt +++ b/requirements/typing.txt @@ -1,4 +1,4 @@ -mypy~=2.4.0 +mypy types-jsonschema types-requests types-Flask