diff --git a/guppylang-internals/src/guppylang_internals/std/_internal/moved.py b/guppylang-internals/src/guppylang_internals/std/_internal/moved.py new file mode 100644 index 000000000..6be1ba2fd --- /dev/null +++ b/guppylang-internals/src/guppylang_internals/std/_internal/moved.py @@ -0,0 +1,46 @@ +from collections.abc import Callable +from typing import Any, ParamSpec, TypeVar + +from typing_extensions import Self + +P = ParamSpec("P") +Out = TypeVar("Out") + + +def produce_moved_function( + module: str, old_name: str, new_location: str +) -> Callable[P, Out]: + """Produces a function that raises an import error when used, stating that it + cannot be used any more from the current location. This is a temporary migration + mechanism, and should be considered for removal several months after the move.""" + + def moved_function(*_args: P.args, **_kwargs: P.kwargs) -> Out: + raise ImportError( + f"The function `{old_name}` has been moved to `{new_location}`, and " + f"can no longer be imported from `{module}`." + ) + + return moved_function + + +def produce_moved_class(module: str, old_name: str, new_location: str) -> type: + """Produces a class that raises an import error when instantiated, stating that it + cannot be used any more from the current location. This is a temporary migration + mechanism, and should be considered for removal several months after the move.""" + + class MovedClass: + def __new__(cls, *_args: P.args, **_kwargs: P.kwargs) -> Self: # type: ignore[valid-type] + raise ImportError( + f"The class `{old_name}` has been moved to `{new_location}`, and " + f"can no longer be imported from `{module}`." + ) + + def __class_getitem__(cls, item: Any) -> type: + # Gracefully handles subscripting of the type in positions that are + # evaluated by the Python interpreter + raise ImportError( + f"The class `{old_name}` has been moved to `{new_location}`, and " + f"can no longer be imported from `{module}`." + ) + + return MovedClass diff --git a/guppylang/src/guppylang/std/builtins.py b/guppylang/src/guppylang/std/builtins.py index 312db7cfd..92d11ca86 100644 --- a/guppylang/src/guppylang/std/builtins.py +++ b/guppylang/src/guppylang/std/builtins.py @@ -1,8 +1,13 @@ """Reexports core types and functions that are available without an explicit import.""" -from guppylang.std.array import ArrayIter, FrozenarrayIter, array, frozenarray +from guppylang_internals.std._internal.moved import ( + produce_moved_class, + produce_moved_function, +) + +from guppylang.std.array import array, frozenarray from guppylang.std.bool import bool -from guppylang.std.iter import Range, SizedIter, range +from guppylang.std.iter import range from guppylang.std.lang import ( Controllable, Daggerable, @@ -15,11 +20,8 @@ py, ) from guppylang.std.list import list -from guppylang.std.mem import mem_swap from guppylang.std.num import ( abs, - bytecast_float_to_nat, - bytecast_nat_to_float, divmod, float, int, @@ -29,7 +31,7 @@ round, ) from guppylang.std.option import Option, nothing, some -from guppylang.std.platform import barrier, exit, output, panic, result +from guppylang.std.platform import exit, output, panic, result from guppylang.std.quantum import qubit from guppylang.std.reflection import callable from guppylang.std.string import str @@ -93,6 +95,23 @@ zip, ) +# TODO remove once https://github.com/Quantinuum/guppylang/issues/1019 has been resolved +# for a while +mem_swap = produce_moved_function(__name__, "mem_swap", "guppylang.std.mem") # type: ignore[var-annotated] +bytecast_float_to_nat = produce_moved_function( # type: ignore[var-annotated] + __name__, "bytecast_float_to_nat", "guppylang.std.num" +) +bytecast_nat_to_float = produce_moved_function( # type: ignore[var-annotated] + __name__, "bytecast_nat_to_float", "guppylang.std.num" +) +barrier = produce_moved_function(__name__, "barrier", "guppylang.std.platform") # type: ignore[var-annotated] +Range = produce_moved_class(__name__, "Range", "guppylang.std.iter") +SizedIter = produce_moved_class(__name__, "SizedIter", "guppylang.std.iter") +ArrayIter = produce_moved_class(__name__, "ArrayIter", "guppylang.std.array") +FrozenarrayIter = produce_moved_class( + __name__, "FrozenarrayIter", "guppylang.std.array" +) + __all__ = ( # noqa: RUF022 "__import__", "abs", @@ -170,7 +189,6 @@ "round", "set", "setattr", - "SizedIter", "slice", "some", "sorted", @@ -184,12 +202,4 @@ "Unitary", "Controllable", "Daggerable", - # TODO: Remove the following from prelude - "ArrayIter", # Deprecated reexport - "barrier", # Deprecated reexport - "bytecast_float_to_nat", # Deprecated reexport - "bytecast_nat_to_float", # Deprecated reexport - "FrozenarrayIter", # Deprecated reexport - "mem_swap", # Deprecated reexport - "Range", # Deprecated reexport ) diff --git a/guppylang/src/guppylang/std/collections/stack.py b/guppylang/src/guppylang/std/collections/stack.py index ec5aef252..c6e8bc77c 100644 --- a/guppylang/src/guppylang/std/collections/stack.py +++ b/guppylang/src/guppylang/std/collections/stack.py @@ -2,6 +2,10 @@ from typing import TYPE_CHECKING, Generic, no_type_check +from guppylang_internals.std._internal.moved import ( + produce_moved_class, + produce_moved_function, +) from typing_extensions import Self from guppylang.decorator import guppy @@ -119,8 +123,15 @@ def empty_stack() -> Stack[T, MAX_SIZE]: return Stack(buf, 0) -# Deprecated reexport -from guppylang.std.collections.priority_queue import ( # noqa: F401 E402 - PriorityQueue, - empty_priority_queue, +# TODO remove once https://github.com/Quantinuum/guppylang/issues/1019 has been resolved +# for a while +PriorityQueue = produce_moved_class( + "guppylang.std.collections.stack", + "PriorityQueue", + "guppylang.std.collections.priority_queue", +) +empty_priority_queue = produce_moved_function( # type: ignore[var-annotated] + "guppylang.std.collections.stack", + "empty_priority_queue", + "guppylang.std.collections.priority_queue", ) diff --git a/guppylang/src/guppylang/std/quantum_functional.py b/guppylang/src/guppylang/std/quantum_functional.py index 5d88ce1bf..2c1457a48 100644 --- a/guppylang/src/guppylang/std/quantum_functional.py +++ b/guppylang/src/guppylang/std/quantum_functional.py @@ -1,49 +1,5 @@ -"""Deprecated: Use `guppylang.std.quantum.functional` instead.""" - -from guppylang.std.quantum.functional import ( - ch, - crz, - cx, - cy, - cz, - h, - project_z, - reset, - rx, - ry, - rz, - s, - sdg, - t, - tdg, - toffoli, - v, - vdg, - x, - y, - z, -) - -__all__ = ( - "ch", - "crz", - "cx", - "cy", - "cz", - "h", - "project_z", - "reset", - "rx", - "ry", - "rz", - "s", - "sdg", - "t", - "tdg", - "toffoli", - "v", - "vdg", - "x", - "y", - "z", +# TODO remove once https://github.com/Quantinuum/guppylang/issues/1019 has been resolved +# for a while +raise ImportError( + "`guppylang.std.quantum_functional` has been removed. Import from `guppylang.std.quantum_functional` instead." # noqa: E501 ) diff --git a/tests/integration/test_range.py b/tests/integration/test_range.py index 0adf2ebb5..c9ea9ec22 100644 --- a/tests/integration/test_range.py +++ b/tests/integration/test_range.py @@ -1,8 +1,8 @@ import builtins from guppylang.decorator import guppy -from guppylang.std.builtins import range, SizedIter, py -from guppylang.std.iter import Range +from guppylang.std.builtins import range, py +from guppylang.std.iter import Range, SizedIter def test_range(run_int_fn): diff --git a/tests/test_removed.py b/tests/test_removed.py new file mode 100644 index 000000000..e06941287 --- /dev/null +++ b/tests/test_removed.py @@ -0,0 +1,109 @@ +import pytest + + +def test_removed_quantum_functional(): + with pytest.raises( + ImportError, + match=r"`guppylang.std.quantum_functional` has been removed. Import from `guppylang.std.quantum_functional` instead.", # noqa: E501 + ): + import guppylang.std.quantum_functional # noqa: F401 + + +def test_removed_mem_swap(): + from guppylang.std.builtins import mem_swap + + with pytest.raises( + ImportError, + match=r"The function `mem_swap` has been moved to `guppylang.std.mem`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + mem_swap(1, 2) + + +def test_removed_bytecast_float_to_nat(): + from guppylang.std.builtins import bytecast_float_to_nat + + with pytest.raises( + ImportError, + match=r"The function `bytecast_float_to_nat` has been moved to `guppylang.std.num`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + bytecast_float_to_nat(1.0) + + +def test_removed_bytecast_nat_to_float(): + from guppylang.std.builtins import bytecast_nat_to_float + + with pytest.raises( + ImportError, + match=r"The function `bytecast_nat_to_float` has been moved to `guppylang.std.num`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + bytecast_nat_to_float(1) + + +def test_removed_barrier(): + from guppylang.std.builtins import barrier + + with pytest.raises( + ImportError, + match=r"The function `barrier` has been moved to `guppylang.std.platform`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + barrier() + + +def test_removed_Range(): + from guppylang.std.builtins import Range + + with pytest.raises( + ImportError, + match=r"The class `Range` has been moved to `guppylang.std.iter`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + Range() + + +def test_removed_SizedIter(): + from guppylang.std.builtins import SizedIter + + with pytest.raises( + ImportError, + match=r"The class `SizedIter` has been moved to `guppylang.std.iter`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + SizedIter() + + +def test_removed_ArrayIter(): + from guppylang.std.builtins import ArrayIter + + with pytest.raises( + ImportError, + match=r"The class `ArrayIter` has been moved to `guppylang.std.array`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + ArrayIter() + + +def test_removed_FrozenArrayIter(): + from guppylang.std.builtins import FrozenarrayIter + + with pytest.raises( + ImportError, + match=r"The class `FrozenarrayIter` has been moved to `guppylang.std.array`, and can no longer be imported from `guppylang.std.builtins`.", # noqa: E501 + ): + FrozenarrayIter() + + +def test_removed_PriorityQueue(): + from guppylang.std.collections.stack import PriorityQueue + + with pytest.raises( + ImportError, + match=r"The class `PriorityQueue` has been moved to `guppylang.std.collections.priority_queue`, and can no longer be imported from `guppylang.std.collections.stack`.", # noqa: E501 + ): + PriorityQueue() + + +def test_removed_empty_priority_queue(): + from guppylang.std.collections.stack import empty_priority_queue + + with pytest.raises( + ImportError, + match=r"The function `empty_priority_queue` has been moved to `guppylang.std.collections.priority_queue`, and can no longer be imported from `guppylang.std.collections.stack`.", # noqa: E501 + ): + empty_priority_queue()