diff --git a/edb/common/checked.py b/edb/common/checked.py index 68983f3fe4a..4ef8948ff03 100644 --- a/edb/common/checked.py +++ b/edb/common/checked.py @@ -28,7 +28,6 @@ MutableSequence, MutableSet, Sequence, - cast, overload, ) @@ -36,7 +35,6 @@ import itertools import types -from edb.common import debug from edb.common import parametric @@ -78,16 +76,6 @@ class AbstractCheckedList[T]: type: type _container: list[T] - @classmethod - def _check_type(cls, value: Any) -> T: - """Ensure `value` is of type T and return it.""" - if not isinstance(value, cls.type): - raise ValueError( - f"{cls!r} accepts only values of type {cls.type!r}, " - f"got {type(value)!r}" - ) - return cast(T, value) - def __init__(self, iterable: Iterable[T] = ()) -> None: pass @@ -129,7 +117,7 @@ class FrozenCheckedList[T]( ): def __init__(self, iterable: Iterable[T] = ()) -> None: super().__init__() - self._container = [self._check_type(element) for element in iterable] + self._container = [element for element in iterable] self._hash_cache = -1 def __hash__(self) -> int: @@ -180,7 +168,7 @@ class CheckedList[T]( ): def __init__(self, iterable: Iterable[T] = ()) -> None: super().__init__() - self._container = [self._check_type(element) for element in iterable] + self._container = [element for element in iterable] # # Sequence @@ -210,11 +198,11 @@ def __setitem__(self, index: slice, value: Iterable[T]) -> None: ... def __setitem__(self, index: int | slice, value: Any) -> None: if isinstance(index, int): - self._container[index] = self._check_type(value) + self._container[index] = value return _slice = index - self._container[_slice] = filter(self._check_type, value) + self._container[_slice] = value @overload def __delitem__(self, index: int) -> None: ... @@ -226,7 +214,7 @@ def __delitem__(self, index: int | slice) -> None: del self._container[index] def insert(self, index: int, value: T) -> None: - self._container.insert(index, self._check_type(value)) + self._container.insert(index, value) def __len__(self) -> int: return len(self._container) @@ -242,7 +230,7 @@ def __radd__(self, other: Iterable[T]) -> CheckedList[T]: return self.__class__(itertools.chain(other, self)) def __iadd__(self, other: Iterable[T]) -> CheckedList[T]: - self._container.extend(filter(self._check_type, other)) + self._container.extend(other) return self def __mul__(self, n: int) -> CheckedList[T]: @@ -265,16 +253,6 @@ class AbstractCheckedSet[T](AbstractSet[T]): def __init__(self, iterable: Iterable[T] = ()) -> None: pass - @classmethod - def _check_type(cls, value: Any) -> T: - """Ensure `value` is of type T and return it.""" - if not isinstance(value, cls.type): - raise ValueError( - f"{cls!r} accepts only values of type {cls.type!r}, " - f"got {type(value)!r}" - ) - return cast(T, value) - def _cast(self, other: Any) -> AbstractSet[T]: if isinstance(other, (FrozenCheckedSet, CheckedSet)): return other._container @@ -326,7 +304,7 @@ class FrozenCheckedSet[T]( ): def __init__(self, iterable: Iterable[T] = ()) -> None: super().__init__() - self._container = {self._check_type(element) for element in iterable} + self._container = {element for element in iterable} self._hash_cache = -1 def __hash__(self) -> int: @@ -347,10 +325,6 @@ def __hash__(self) -> int: def __and__(self, other: AbstractSet[T]) -> FrozenCheckedSet[T]: other_set = self._cast(other) - for elem in other_set: - # We need the explicit type check to reject nonsensical - # & operations that must always result in an empty new set. - self._check_type(elem) return self.__class__(other_set & self._container) __rand__ = __and__ @@ -365,10 +339,6 @@ def __or__( # type: ignore def __sub__(self, other: AbstractSet[T]) -> FrozenCheckedSet[T]: other_set = self._cast(other) - for elem in other_set: - # We need the explicit type check to reject nonsensical - # - operations that always return the original checked set. - self._check_type(elem) return self.__class__(self._container - other_set) def __rsub__(self, other: AbstractSet[T]) -> FrozenCheckedSet[T]: @@ -403,7 +373,7 @@ class CheckedSet[T]( def __init__(self, iterable: Iterable[T] = ()) -> None: super().__init__() - self._container = {self._check_type(element) for element in iterable} + self._container = {element for element in iterable} # # Replaced mixins of collections.abc.Set @@ -418,10 +388,6 @@ def __init__(self, iterable: Iterable[T] = ()) -> None: def __and__(self, other: AbstractSet[T]) -> CheckedSet[T]: other_set = self._cast(other) - for elem in other_set: - # We need the explicit type check to reject nonsensical - # & operations that must always result in an empty new set. - self._check_type(elem) return self.__class__(other_set & self._container) __rand__ = __and__ @@ -434,10 +400,6 @@ def __or__(self, other: AbstractSet[T]) -> CheckedSet[T]: # type: ignore def __sub__(self, other: AbstractSet[T]) -> CheckedSet[T]: other_set = self._cast(other) - for elem in other_set: - # We need the explicit type check to reject nonsensical - # - operations that always return the original checked set. - self._check_type(elem) return self.__class__(self._container - other_set) def __rsub__(self, other: AbstractSet[T]) -> CheckedSet[T]: @@ -455,33 +417,29 @@ def __xor__(self, other: AbstractSet[T]) -> CheckedSet[T]: # type: ignore # def add(self, value: T) -> None: - self._container.add(self._check_type(value)) + self._container.add(value) def discard(self, value: T) -> None: - self._container.discard(self._check_type(value)) + self._container.discard(value) # # Replaced mixins of collections.abc.MutableSet # def __ior__(self, other: AbstractSet[T]) -> CheckedSet[T]: # type: ignore - self._container |= set(filter(self._check_type, other)) + self._container |= set(other) return self def __iand__(self, other: AbstractSet[T]) -> CheckedSet[T]: - # We do the type check here to reject nonsensical - # & operations that always clear the checked set. - self._container &= set(filter(self._check_type, other)) + self._container &= set(other) return self def __ixor__(self, other: AbstractSet[T]) -> CheckedSet[T]: # type: ignore - self._container ^= set(filter(self._check_type, other)) + self._container ^= set(other) return self def __isub__(self, other: AbstractSet[T]) -> CheckedSet[T]: - # We do the type check here to reject nonsensical - # - operations that could never affect the checked set. - self._container -= set(filter(self._check_type, other)) + self._container -= set(other) return self # @@ -518,26 +476,6 @@ class AbstractCheckedDict[K, V]: valuetype: type _container: dict[K, V] - @classmethod - def _check_key_type(cls, key: Any) -> K: - """Ensure `key` is of type K and return it.""" - if not isinstance(key, cls.keytype): - raise KeyError( - f"{cls!r} accepts only keys of type {cls.keytype!r}, " - f"got {type(key)!r}" - ) - return cast(K, key) - - @classmethod - def _check_value_type(cls, value: Any) -> V: - """Ensure `value` is of type V and return it.""" - if not isinstance(value, cls.valuetype): - raise ValueError( - f"{cls!r} accepts only values of type " - "{cls.valuetype!r}, got {type(value)!r}" - ) - return cast(V, value) - def __eq__(self, other: object) -> bool: if isinstance(other, CheckedDict): other = other._container @@ -590,8 +528,7 @@ def __len__(self) -> int: # def __setitem__(self, key: K, value: V) -> None: - self._check_key_type(key) - self._container[key] = self._check_value_type(value) + self._container[key] = value def __delitem__(self, key: K) -> None: del self._container[key] @@ -603,40 +540,8 @@ def __delitem__(self, key: K) -> None: @classmethod def fromkeys( cls, iterable: Iterable[K], value: Optional[V] = None - ) -> CheckedDict[K, V]: - new: CheckedDict[K, V] = cls() + ) -> CheckedDict[K, V | None]: + new: CheckedDict[K, V | None] = cls() # type: ignore for key in iterable: - new[cls._check_key_type(key)] = cls._check_value_type(value) + new[key] = value return new - - -def _identity[T](cls: type, value: T) -> T: - return value - - -_type_checking = { - CheckedList: ["_check_type"], - CheckedDict: ["_check_key_type", "_check_value_type"], - CheckedSet: ["_check_type"], - FrozenCheckedList: ["_check_type"], - FrozenCheckedSet: ["_check_type"], -} - - -def disable_typechecks() -> None: - for type_, methods in _type_checking.items(): - for method in methods: - setattr(type_, method, _identity) - - -def enable_typechecks() -> None: - for type_, methods in _type_checking.items(): - for method in methods: - try: - delattr(type_, method) - except AttributeError: - continue - - -if not debug.flags.typecheck: - disable_typechecks() diff --git a/edb/common/ordered.py b/edb/common/ordered.py index 492f2f89ab4..cf281233faa 100644 --- a/edb/common/ordered.py +++ b/edb/common/ordered.py @@ -27,7 +27,6 @@ MutableSet, ) -import collections import collections.abc diff --git a/edb/language_server/definition.py b/edb/language_server/definition.py index 9a470a29e96..dcf3ae014b7 100644 --- a/edb/language_server/definition.py +++ b/edb/language_server/definition.py @@ -19,7 +19,6 @@ from typing import Optional from lsprotocol import types as lsp_types -import pygls import pygls.workspace from edb.common import span as edb_span diff --git a/edb/language_server/schema.py b/edb/language_server/schema.py index 91acd85568f..0dc25232774 100644 --- a/edb/language_server/schema.py +++ b/edb/language_server/schema.py @@ -21,7 +21,7 @@ import os from pygls import uris as pygls_uris -import pygls +import pygls.workspace from lsprotocol import types as lsp_types @@ -32,7 +32,6 @@ from edb.schema import schema as s_schema from edb.schema import std as s_std from edb.schema import ddl as s_ddl -import pygls.workspace from . import parsing as ls_parsing from . import is_schema_file diff --git a/edb/schema/expr.py b/edb/schema/expr.py index addb5a69991..6cb6be92a79 100644 --- a/edb/schema/expr.py +++ b/edb/schema/expr.py @@ -448,7 +448,7 @@ def __repr__(self) -> str: return f'' -class ExpressionList(checked.FrozenCheckedList[Expression]): +class ExpressionList(list[Expression]): @staticmethod def merge_values( diff --git a/edb/schema/types.py b/edb/schema/types.py index 3edf6a1a792..a9e64dedae2 100644 --- a/edb/schema/types.py +++ b/edb/schema/types.py @@ -1262,7 +1262,6 @@ def as_type_delete_if_unused( ) -Dimensions = checked.FrozenCheckedList[int] Array_T = typing.TypeVar("Array_T", bound="Array") Array_T_co = typing.TypeVar("Array_T_co", bound="Array", covariant=True) @@ -1332,7 +1331,7 @@ class Array( ) dimensions = so.SchemaField( - Dimensions, + checked.FrozenCheckedList[int], coerce=True, # We want a low compcoef so that array types are *never* altered. compcoef=0, diff --git a/edb/tools/test/runner.py b/edb/tools/test/runner.py index 10f2bd03fe6..4a35262e3df 100644 --- a/edb/tools/test/runner.py +++ b/edb/tools/test/runner.py @@ -32,7 +32,6 @@ import json import multiprocessing import multiprocessing.reduction -import multiprocessing.util import os import pathlib import random @@ -46,7 +45,6 @@ import types import unittest.case import unittest.result -import unittest.runner import unittest.signals import warnings diff --git a/tests/common/test_checked.py b/tests/common/test_checked.py deleted file mode 100644 index a418adfc226..00000000000 --- a/tests/common/test_checked.py +++ /dev/null @@ -1,448 +0,0 @@ -# mypy: ignore-errors - -# -# This source file is part of the EdgeDB open source project. -# -# Copyright 2011-present MagicStack Inc. and the EdgeDB authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations -from typing import TypeVar - -import pickle -import sys -import unittest - -from edb.common.checked import CheckedDict -from edb.common.checked import CheckedList -from edb.common.checked import CheckedSet -from edb.common.checked import FrozenCheckedList -from edb.common.checked import FrozenCheckedSet -from edb.common.checked import enable_typechecks, disable_typechecks -from edb.common import debug - - -class EnsureTypeChecking: - def setUp(self): - if not debug.flags.typecheck: - enable_typechecks() - - def tearDown(self): - if not debug.flags.typecheck: - disable_typechecks() - - -class CheckedDictTests(EnsureTypeChecking, unittest.TestCase): - def test_common_checked_checkeddict_basics(self) -> None: - StrDict = CheckedDict[str, int] - assert StrDict({"1": 2})["1"] == 2 - assert StrDict(foo=1, initdict=2)["initdict"] == 2 - - sd = StrDict(**{"1": 2}) - assert sd["1"] == 2 - - assert dict(sd) == {"1": 2} - - sd["foo"] = 42 - - with self.assertRaises(KeyError): - sd[0] = 0 - with self.assertRaises(ValueError): - sd["foo"] = "bar" - assert sd["foo"] == 42 - - with self.assertRaises(ValueError): - sd.update({"spam": "ham"}) - - sd.update({"spam": 12}) - assert sd["spam"] == 12 - - with self.assertRaises(ValueError): - StrDict(**{"foo": "bar"}) - - with self.assertRaisesRegex(TypeError, "expects 2 type parameters"): - # no value type given - CheckedDict[int] - - class Foo: - def __repr__(self): - return self.__class__.__name__ - - class Bar(Foo): - pass - - FooDict = CheckedDict[str, Foo] - - td = FooDict(bar=Bar(), foo=Foo()) - module_path = self.__module__ - expected = ( - f"edb.common.checked.CheckedDict[str, {module_path}." - "CheckedDictTests.test_common_checked_checkeddict_basics." - ".Foo]({'bar': Bar, 'foo': Foo})" - ) - assert repr(td) == expected - expected = "{'bar': Bar, 'foo': Foo}" - assert str(td) == expected - - with self.assertRaisesRegex(ValueError, "expected at most 1"): - FooDict(Foo(), Bar()) - - td = FooDict.fromkeys("abc", value=Bar()) - assert len(td) == 3 - del td["b"] - assert "b" not in td - assert len(td) == 2 - assert str(td) == "{'a': Bar, 'c': Bar}" - - def test_common_checked_checkeddict_pickling(self) -> None: - StrDict = CheckedDict[str, int] - sd = StrDict() - sd["foo"] = 123 - sd["bar"] = 456 - - assert sd.keytype is str and sd.valuetype is int - assert type(sd) is StrDict - assert sd["foo"] == 123 - assert sd["bar"] == 456 - - sd2 = pickle.loads(pickle.dumps(sd)) - - assert sd2.keytype is str and sd2.valuetype is int - assert type(sd2) is StrDict - assert sd2["foo"] == 123 - assert sd2["bar"] == 456 - assert sd is not sd2 - assert sd == sd2 - - -class CheckedListTestBase(EnsureTypeChecking): - BaseList = FrozenCheckedList - - def test_common_checked_shared_list_basics(self) -> None: - IntList = self.BaseList[int] - StrList = self.BaseList[str] - - with self.assertRaises(ValueError): - IntList(("1", "2")) - - with self.assertRaises(ValueError): - StrList([1]) - - with self.assertRaises(ValueError): - StrList([None]) - - sl = StrList(["Some", "strings", "here"]) - assert sl == ["Some", "strings", "here"] - assert list(sl) == ["Some", "strings", "here"] - assert sl > ["Some", "strings"] - assert sl < ["Some", "strings", "here", "too"] - assert sl >= ["Some", "strings"] - assert sl <= ["Some", "strings", "here", "too"] - assert sl >= ["Some", "strings", "here"] - assert sl <= StrList(["Some", "strings", "here"]) - assert sl + ["too"] == ["Some", "strings", "here", "too"] - assert ["Hey"] + sl == ["Hey", "Some", "strings", "here"] - assert type(sl + ["too"]) is StrList - assert type(["Hey"] + sl) is StrList - assert sl[0] == "Some" - assert type(sl[:2]) is StrList - assert sl[:2] == StrList(["Some", "strings"]) - assert len(sl) == 3 - assert sl[1:2] * 3 == ["strings", "strings", "strings"] - assert 3 * sl[1:2] == ["strings", "strings", "strings"] - assert type(3 * sl[1:2]) is StrList - - class Foo: - def __repr__(self): - return self.__class__.__name__ - - class Bar(Foo): - pass - - FooList = self.BaseList[Foo] - - tl = FooList([Bar(), Foo()]) - cls_name = self.BaseList.__name__ - module_path = self.__module__ - expected = ( - f"edb.common.checked.{cls_name}[{module_path}." - "CheckedListTestBase.test_common_checked_shared_list_basics." - ".Foo]([Bar, Foo])" - ) - assert repr(tl) == expected, repr(tl) - expected = "[Bar, Foo]" - assert str(tl) == expected - - def test_common_checked_shared_list_pickling(self): - StrList = self.BaseList[str] - sd = StrList(["123", "456"]) - - assert sd.type is str - assert type(sd) is StrList - assert sd[0] == "123" - assert sd[1] == "456" - - sd = pickle.loads(pickle.dumps(sd)) - - assert sd.type is str - assert type(sd) is StrList - assert sd[0] == "123" - assert sd[1] == "456" - - def test_common_checked_shared_list_invalid_parameters(self): - with self.assertRaisesRegex(TypeError, "must be parametrized"): - self.BaseList() - - with self.assertRaisesRegex(TypeError, "expects 1 type parameter"): - self.BaseList[int, int]() - - with self.assertRaisesRegex(TypeError, "already parametrized"): - self.BaseList[int][int] - - @unittest.skipUnless(sys.version_info >= (3, 7, 3), "BPO-35992") - def test_common_checked_shared_list_non_type_parameter(self): - with self.assertRaisesRegex(TypeError, "expects types"): - self.BaseList[1]() - - -class FrozenCheckedListTests(CheckedListTestBase, unittest.TestCase): - BaseList = FrozenCheckedList - - def test_common_checked_frozenlist_basics(self) -> None: - StrList = self.BaseList[str] - sl = StrList(["1", "2"]) - with self.assertRaises(AttributeError): - sl.append("3") - - def test_common_checked_frozenlist_hashable(self) -> None: - StrList = self.BaseList[str] - s1 = StrList(["1", "2"]) - s2 = StrList(["1", "2"]) - self.assertEqual(hash(s1), hash(tuple(s1))) - self.assertEqual(hash(s1), hash(s2)) - - -class CheckedListTests(CheckedListTestBase, unittest.TestCase): - BaseList = CheckedList - - def test_common_checked_checkedlist_basics(self) -> None: - StrList = self.BaseList[str] - tl = StrList() - tl.append("1") - tl.extend(("2", "3")) - tl += ["4"] - tl += ("5",) - tl = tl + ("6",) - tl = ("0",) + tl - tl.insert(0, "-1") - assert tl == ["-1", "0", "1", "2", "3", "4", "5", "6"] - del tl[1] - assert tl == ["-1", "1", "2", "3", "4", "5", "6"] - del tl[1:3] - assert tl == ["-1", "3", "4", "5", "6"] - tl[2] = "X" - assert tl == ["-1", "3", "X", "5", "6"] - tl[1:4] = ("A", "B", "C") - assert tl == ["-1", "A", "B", "C", "6"] - tl *= 2 - assert tl == ["-1", "A", "B", "C", "6", "-1", "A", "B", "C", "6"] - tl.sort() - assert tl == ["-1", "-1", "6", "6", "A", "A", "B", "B", "C", "C"] - - with self.assertRaises(ValueError): - tl.append(42) - - with self.assertRaises(ValueError): - tl.extend((42,)) - - with self.assertRaises(ValueError): - tl.insert(0, 42) - - with self.assertRaises(ValueError): - tl += (42,) - - with self.assertRaises(ValueError): - tl = tl + (42,) - - with self.assertRaises(ValueError): - tl = (42,) + tl - - -class CheckedSetTestBase(EnsureTypeChecking): - BaseSet = FrozenCheckedSet - - def test_common_checked_shared_set_basics(self) -> None: - StrSet = self.BaseSet[str] - s1 = StrSet("sphinx of black quartz judge my vow") - assert s1 == set("abcdefghijklmnopqrstuvwxyz ") - s2 = StrSet("hunter2") - assert (s1 & s2) == StrSet("hunter") - assert type(s1 & s2) is StrSet - assert (s1 | s2) == set("abcdefghijklmnopqrstuvwxyz 2") - assert type(s1 | s2) is StrSet - assert (s1 - s2) == set("abcdfgijklmopqsvwxyz ") - assert type(s1 - s2) is StrSet - assert (set("hunter2") - s1) == StrSet("2") - assert type(set("hunter2") - s1) is StrSet - - class Foo: - def __repr__(self): - return self.__class__.__name__ - - class Bar(Foo): - def __eq__(self, other): - return isinstance(other, Bar) - - def __hash__(self): - return 1 - - FooSet = self.BaseSet[Foo] - - tl = FooSet([Bar(), Foo(), Bar()]) - tl2 = FooSet(tl | {Foo()}) - assert len(tl) == 2 - assert len(tl ^ tl2) == 1 - assert tl.issuperset({Bar()}) - assert tl.issubset(tl2) - # We have to do some gymnastics due to sets being unordered. - expected = {"{Bar, Foo}", "{Foo, Bar}"} - assert str(tl) in expected - cls_name = self.BaseSet.__name__ - module_path = self.__module__ - expected_template = ( - f"edb.common.checked.{cls_name}[{module_path}." - "CheckedSetTestBase.test_common_checked_shared_set_basics." - ".Foo]({})" - ) - assert repr(tl) in {expected_template.format(e) for e in expected} - - def test_common_checkedset_pickling(self): - StrSet = self.BaseSet[str] - sd = StrSet({"123", "456"}) - - self.assertIs(sd.type, str) - self.assertIs(type(sd), StrSet) - self.assertIn("123", sd) - self.assertIn("456", sd) - - sd = pickle.loads(pickle.dumps(sd)) - - self.assertIs(sd.type, str) - self.assertIs(type(sd), StrSet) - self.assertIn("123", sd) - self.assertIn("456", sd) - - -class FrozenCheckedSetTests(CheckedSetTestBase, unittest.TestCase): - BaseSet = FrozenCheckedSet - - def test_common_checked_frozenset_hashable(self) -> None: - StrSet = self.BaseSet[str] - s1 = StrSet(["1", "2"]) - s2 = StrSet(["2", "1"]) - self.assertEqual(hash(s1), hash(frozenset(("1", "2")))) - self.assertEqual(hash(s1), hash(s2)) - - -class CheckedSetTests(CheckedSetTestBase, unittest.TestCase): - BaseSet = CheckedSet - - def test_common_checked_checkedset_basics(self) -> None: - StrSet = self.BaseSet[str] - tl = StrSet() - tl.add("1") - tl.update(("2", "3")) - tl |= ["4"] - tl |= ("5",) - tl = tl | StrSet(["6"]) - tl = {"0"} | tl - assert set(tl) == {"0", "1", "2", "3", "4", "5", "6"} - - tl = "67896789" - tl # sic, TypedSet used to coerce arguments, too. - assert tl == {"7", "8", "9"} - assert set(tl - {"8", "9"}) == {"7"} - - assert set(tl ^ {"8", "9", "10"}) == {"7", "10"} - assert set({"8", "9", "10"} ^ tl) == {"7", "10"} - tl -= {"8"} - assert tl == StrSet("79") - - with self.assertRaises(ValueError): - tl.add(42) - - with self.assertRaises(ValueError): - tl.update((42,)) - - with self.assertRaises(ValueError): - tl |= {42} - - with self.assertRaises(ValueError): - tl = tl | {42} - - with self.assertRaises(ValueError): - tl = {42} | tl - - with self.assertRaises(ValueError): - tl = {42} ^ tl - - with self.assertRaises(ValueError): - tl &= {42} - - with self.assertRaises(ValueError): - tl ^= {42} - - -T = TypeVar("T") - - -class ConcreteFrozenCheckedSetSubclass1(FrozenCheckedSet[int]): - def sum(self) -> int: - return sum(elem for elem in self) - - -class GenericFrozenCheckedSetSubclass(FrozenCheckedSet[T]): - def sum(self) -> T: - return sum(elem for elem in self) - - -ConcreteFrozenCheckedSetSubclass2 = GenericFrozenCheckedSetSubclass[int] - - -class CheckedSubclassingTestBase(EnsureTypeChecking): - BaseSet = GenericFrozenCheckedSetSubclass - - def test_common_checked_checkedset_subclass_pickling(self): - cfcss = self.BaseSet([0, 2, 4, 6, 8]) - self.assertIs(cfcss.type, int) - self.assertIs(type(cfcss), self.BaseSet) - self.assertEqual(cfcss, {0, 2, 4, 6, 8}) - self.assertEqual(cfcss.sum(), 20) - - pickled = pickle.dumps(cfcss) - cfcss2 = pickle.loads(pickled) - - self.assertTrue(cfcss2.type, int) - self.assertIs(type(cfcss2), self.BaseSet) - self.assertIsNot(cfcss, cfcss2) - self.assertEqual(cfcss, cfcss2) - self.assertEqual(cfcss.sum(), 20) - - -class CheckedSubclass1Tests(CheckedSubclassingTestBase, unittest.TestCase): - BaseSet = ConcreteFrozenCheckedSetSubclass1 - - -class CheckedSubclass2Tests(CheckedSubclassingTestBase, unittest.TestCase): - BaseSet = ConcreteFrozenCheckedSetSubclass2