diff --git a/.basedpyright/baseline.json b/.basedpyright/baseline.json index 96c317c..2d85f22 100644 --- a/.basedpyright/baseline.json +++ b/.basedpyright/baseline.json @@ -379,30 +379,6 @@ "lineCount": 1 } }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, { "code": "reportIncompatibleMethodOverride", "range": { @@ -410,166 +386,6 @@ "endColumn": 14, "lineCount": 1 } - }, - { - "code": "reportIncompatibleMethodOverride", - "range": { - "startColumn": 8, - "endColumn": 14, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 19, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 38, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 37, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 37, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 36, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 23, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 22, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 38, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 37, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 37, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 36, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 23, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 22, - "lineCount": 1 - } - }, - { - "code": "reportOverlappingOverload", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } } ], "./islpy/_monkeypatch.py": [ diff --git a/gen_wrap.py b/gen_wrap.py index 3a698a5..3c853fb 100644 --- a/gen_wrap.py +++ b/gen_wrap.py @@ -1468,41 +1468,6 @@ def write_exposer( f' isl::handle_isl_error(ctx, "isl_{meth.cls}_read_from_str");' '}, py::arg("s"), py::arg("context").none(true)=py::none());\n') - # Handle auto-self-downcasts. These are deprecated. - if not meth.is_static: - for basic_cls in AUTO_DOWNCASTS.get(meth.cls, []): - basic_overloads = meth_to_overloads.setdefault((basic_cls, meth.name), []) - if any(basic_meth - for basic_meth in basic_overloads - if (basic_meth.is_static - or meth.arg_types()[1:] == basic_meth.arg_types()[1:]) - ): - continue - - # These are high-traffic APIs that are manually implemented - # and not subject to deprecation. - if basic_cls == "basic_set": - if meth.name in ["is_params", "get_hash"]: - continue - elif basic_cls == "basic_map" and meth.name in ["get_hash"]: - continue - - basic_overloads.append(meth) - - downcast_doc_str = (f"{doc_str}\n\nDowncast from " - f":class:`{to_py_class(basic_cls)}` to " - f":class:`{to_py_class(meth.cls)}`.") - escaped_doc_str = downcast_doc_str.replace(newline, escaped_newline) - outf.write(f"// automatic downcast to {meth.cls}\n") - outf.write(f'wrap_{basic_cls}.def(' - # Do not be tempted to pass 'arg_str' here, it will - # prevent implicit conversion. - # https://github.com/wjakob/nanobind/issues/1061 - f'"{py_name}", {func_name}' - f', py::sig("def {py_name}{type_sig}")' - f', "{py_name}{type_sig}\\n{escaped_doc_str}"' - ');\n') - # }}} diff --git a/islpy/_monkeypatch.py b/islpy/_monkeypatch.py index c0cdec3..0e966df 100644 --- a/islpy/_monkeypatch.py +++ b/islpy/_monkeypatch.py @@ -1,4 +1,3 @@ -import os import re from collections.abc import Callable, Collection, Iterable, Mapping, Sequence from functools import update_wrapper @@ -14,7 +13,6 @@ TypeVar, cast, ) -from warnings import warn if TYPE_CHECKING: @@ -68,13 +66,10 @@ SetOrMapT = TypeVar("SetOrMapT", _isl.BasicSet, _isl.Set, _isl.BasicMap, _isl.Map) HasDimNames: TypeAlias = ( - _isl.Space - | _isl.Constraint + _isl.Constraint | _isl.LocalSpace | _isl.Aff - | _isl.MultiAff | _isl.PwAff - | _isl.PwMultiAff | _isl.BasicMap | _isl.BasicSet | _isl.Set @@ -141,7 +136,6 @@ def wrapper(obj: T, *args: P.args, **kwargs: P.kwargs) -> ResultT: def clear_cache(obj: object): object.__delattr__(obj, cache_dict_name) - from functools import update_wrapper new_wrapper = update_wrapper(wrapper, function) # type-ignore because mypy has a point here, stuffing random attributes @@ -854,45 +848,62 @@ def obj_eq(self: IslObject, other: object) -> bool: return self.is_equal(other) -def obj_ne(self: object, other: object) -> bool: - return not self.__eq__(other) +def no_eq(_self: IslObject, _other: object) -> bool: + raise TypeError("equality not available; use manual downcast or try plain_is_equal") for cls in ALL_CLASSES: if hasattr(cls, "is_equal"): cls.__eq__ = obj_eq - cls.__ne__ = obj_ne + else: + cls.__eq__ = no_eq def set_lt(self: _isl.BasicSet | _isl.Set, other: _isl.BasicSet | _isl.Set) -> bool: + if isinstance(self, _isl.BasicSet): + self = self.to_set() return self.is_strict_subset(other) def set_le(self: _isl.BasicSet | _isl.Set, other: _isl.BasicSet | _isl.Set) -> bool: + if isinstance(self, _isl.BasicSet): + self = self.to_set() return self.is_subset(other) def set_gt(self: _isl.BasicSet | _isl.Set, other: _isl.BasicSet | _isl.Set) -> bool: + if isinstance(other, _isl.BasicSet): + other = other.to_set() return other.is_strict_subset(self) def set_ge(self: _isl.BasicSet | _isl.Set, other: _isl.BasicSet | _isl.Set) -> bool: + if isinstance(other, _isl.BasicSet): + other = other.to_set() return other.is_subset(self) def map_lt(self: _isl.BasicMap | _isl.Map, other: _isl.BasicMap | _isl.Map) -> bool: + if isinstance(self, _isl.BasicMap): + self = self.to_map() return self.is_strict_subset(other) def map_le(self: _isl.BasicMap | _isl.Map, other: _isl.BasicMap | _isl.Map) -> bool: + if isinstance(self, _isl.BasicMap): + self = self.to_map() return self.is_subset(other) def map_gt(self: _isl.BasicMap | _isl.Map, other: _isl.BasicMap | _isl.Map) -> bool: + if isinstance(other, _isl.BasicMap): + other = other.to_map() return other.is_strict_subset(self) def map_ge(self: _isl.BasicMap | _isl.Map, other: _isl.BasicMap | _isl.Map) -> bool: + if isinstance(other, _isl.BasicMap): + other = other.to_map() return other.is_subset(self) @@ -1216,57 +1227,3 @@ def _add_functionality() -> None: "Map": "to_map", "UnionMap": "to_union_map", } - - -def _depr_downcast_wrapper( - f: Callable[Concatenate[object, P], ResultT], - ) -> Callable[Concatenate[object, P], ResultT]: - doc = f.__doc__ - assert doc is not None - m = _DOWNCAST_RE.search(doc) - assert m, doc - basic_cls_name = intern(m.group(1)) - tgt_cls_name = m.group(2) - - tgt_cls = cast("type", getattr(_isl, tgt_cls_name)) - is_overload = "Overloaded function" in doc - msg = (f"{basic_cls_name}.{f.__name__} " - f"with implicit conversion of self to {tgt_cls_name} is deprecated " - "and will stop working in 2026. " - f"Explicitly convert to {tgt_cls_name}, " - f"using .{_TO_METHODS[tgt_cls_name]}().") - - if is_overload: - def wrapper(self: object, *args: P.args, **kwargs: P.kwargs) -> ResultT: - # "Try to" detect bad invocations of, e.g., Set.union, which is - # an overload of normal union and UnionSet.union. - if ( - any(isinstance(arg, tgt_cls) for arg in args) - or - any(isinstance(arg, tgt_cls) for arg in kwargs.values()) - ): - warn(msg, DeprecationWarning, stacklevel=2) - - return f(self, *args, **kwargs) - else: - def wrapper(self: object, *args: P.args, **kwargs: P.kwargs) -> ResultT: - warn(msg, DeprecationWarning, stacklevel=2) - - return f(self, *args, **kwargs) - update_wrapper(wrapper, f) - return wrapper - - -def _monkeypatch_self_downcast_deprecation(): - for cls in ALL_CLASSES: - for attr_name in dir(cls): - val = cast("object", getattr(cls, attr_name)) - doc = getattr(val, "__doc__", None) - if doc and "\nDowncast from " in doc: - setattr(cls, attr_name, _depr_downcast_wrapper( - cast("Callable", val), # pyright: ignore[reportMissingTypeArgument] - )) - - -if not os.environ.get("ISLPY_NO_DOWNCAST_DEPRECATION", None): - _monkeypatch_self_downcast_deprecation() diff --git a/pyproject.toml b/pyproject.toml index ae8844d..e11ba6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ [project] name = "islpy" -version = "2026.1" +version = "2026.2" description = "Wrapper around isl, an integer set library" readme = "README.rst" license = "MIT" diff --git a/test/test_isl.py b/test/test_isl.py index 2c4c30f..54742f0 100644 --- a/test/test_isl.py +++ b/test/test_isl.py @@ -96,7 +96,7 @@ def test_upcast(): isl.PwAff(b) - assert b.is_equal(a) + assert b.to_pw_aff().is_equal(a) assert a.is_equal(b) s = isl.BasicSet("[n] -> {[i,j,k]: i<=j + k and (exists m: m=j+k) " @@ -120,7 +120,7 @@ def test_pickling(): inst2 = loads(dumps(inst)) assert inst.space == inst2.space - assert inst.is_equal(inst2) + assert inst.plain_is_equal(inst2) def test_apostrophes_during_pickling(): @@ -209,7 +209,7 @@ def test_schedule(): def callback(node, build): schedulemap = build.get_schedule() - accessmap = accesses.apply_domain(schedulemap) + accessmap = accesses.to_union_map().apply_domain(schedulemap) aff = isl.PwMultiAff.from_map(isl.Map.from_union_map(accessmap)) access = build.call_from_pw_multi_aff(aff) return isl.AstNode.alloc_user(access) @@ -361,8 +361,8 @@ def test_align_spaces(): a1_aligned = isl.align_spaces(a1, a2, obj_bigger_ok=True) a2_aligned = isl.align_spaces(a2, a1) - assert a1_aligned == isl.Aff("[t1, t0, t2] -> { [(32)] }") - assert a2_aligned == isl.Aff("[t1, t0, t2] -> { [(0)] }") + assert a1_aligned.plain_is_equal(isl.Aff("[t1, t0, t2] -> { [(32)] }")) + assert a2_aligned.to_pw_aff().is_equal(isl.PwAff("[t1, t0, t2] -> { [(0)] }")) def test_pass_numpy_int(): @@ -380,8 +380,8 @@ def test_isl_align_two(): a2 = isl.Aff("[t1, t0] -> { [(0)] }") a1_aligned, a2_aligned = isl.align_two(a1, a2) - assert a1_aligned == isl.Aff("[t1, t0, t2] -> { [(32)] }") - assert a2_aligned == isl.Aff("[t1, t0, t2] -> { [(0)] }") + assert a1_aligned.plain_is_equal(isl.Aff("[t1, t0, t2] -> { [(32)] }")) + assert a2_aligned.plain_is_equal(isl.Aff("[t1, t0, t2] -> { [(0)] }")) b1 = isl.BasicSet("[n0, n1, n2] -> { [i0, i1] : }") b2 = isl.BasicSet("[n0, n2, n1, n3] -> { [i1, i0, i2] : }") @@ -436,10 +436,11 @@ def test_union_casts(): s1 = isl.UnionSet("{[0]}") s2 = isl.BasicSet("{[1]}") - s2.union(s1) # works fine + s2u = s2.to_set().to_union_set() + s2u.union(s1) # works fine s1.union(s2) # did not work while #29 was not fixed - assert s2.union(s1) == s1.union(s2) + assert s2u.union(s1) == s1.union(s2) def test_remove_map_if_callback():