From 520b6e2b463b760bc6ce10f54f63f8e6d5c262a4 Mon Sep 17 00:00:00 2001 From: prince Date: Thu, 21 May 2026 00:07:00 +0530 Subject: [PATCH] fix: resolve flaky tenant input validation in Python 3.12 Use instead of for runtime issubclass/isinstance checks in the input validator. The typing module's Sequence can produce flaky isinstance() results in Python 3.12+ due to internal changes in the typing module, causing valid Sequence inputs (e.g., a list of Tenant objects) to be incorrectly rejected. Also adds targeted test coverage for the Sequence[Union[...]] validation pattern that reproduces the reported failure scenario. --- test/collection/test_validator.py | 10 +++++++++- weaviate/validator.py | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/test/collection/test_validator.py b/test/collection/test_validator.py index 1f97548b1..57d08ff25 100644 --- a/test/collection/test_validator.py +++ b/test/collection/test_validator.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import Any, List, Sequence, Union import numpy as np import pandas as pd @@ -28,6 +28,14 @@ False, ), (pl.Series([1, 1]), [_ExtraTypes.PANDAS, _ExtraTypes.NUMPY, List], True), + # Tests for Sequence[Union[...]] pattern, which was flaky in Python 3.12 + (["a", 1], [Sequence[Union[str, int]]], False), + ([1, "a"], [Sequence[Union[str, int]]], False), + ([1, 2], [Sequence[Union[str, int]]], False), + (["a", "b"], [Sequence[Union[str, int]]], False), + (["a", 1], [str, Sequence[Union[str, int]]], False), # matches Sequence[Union[str, int]] + # Non-sequence values are not valid Sequence types: int is not iterable + (42, [Sequence[Union[str, int]]], True), ], ) def test_validator(inputs: Any, expected: List[Any], error: bool) -> None: diff --git a/weaviate/validator.py b/weaviate/validator.py index 7fe11945c..f115427e5 100644 --- a/weaviate/validator.py +++ b/weaviate/validator.py @@ -1,3 +1,4 @@ +from collections.abc import Sequence as ABCSequence from dataclasses import dataclass from typing import Any, List, Sequence, Union, get_args, get_origin @@ -48,9 +49,9 @@ def _is_valid(expected: Any, value: Any) -> bool: args = get_args(expected) return any(isinstance(value, arg) for arg in args) if expected_origin is not None and ( - issubclass(expected_origin, Sequence) or expected_origin is list + issubclass(expected_origin, ABCSequence) or expected_origin is list ): - if not isinstance(value, Sequence) and not isinstance(value, list): + if not isinstance(value, (ABCSequence, list)): return False args = get_args(expected) if len(args) == 1: