diff --git a/docs/usage/configuration.md b/docs/usage/configuration.md index c6af375cc..1ddf8a73e 100644 --- a/docs/usage/configuration.md +++ b/docs/usage/configuration.md @@ -128,7 +128,7 @@ argument "`min`": ```{code-cell} python --- -tags: [warns] +:tags: [raises-exception] --- @magicgui(a_string={'min': 10}) def whoops(a_string: str = 'Hi there'): diff --git a/examples/OLD_napari_image_arithmetic.py b/examples/OLD_napari_image_arithmetic.py deleted file mode 100644 index 04ec34ae2..000000000 --- a/examples/OLD_napari_image_arithmetic.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -!!!!!!!!!!!!!!!!!!!!!!!!!!! -DEPRECATED! DON'T USE THIS -!!!!!!!!!!!!!!!!!!!!!!!!!!! - -This example is just here for aiding in migration to v0.2.0. -see examples/napari_image_arithmetic.py instead - -""" -from enum import Enum - -import numpy -from napari import Viewer, gui_qt -from napari.layers import Image - -from magicgui import magicgui - - -class Operation(Enum): - """A set of valid arithmetic operations for image_arithmetic. - - To create nice dropdown menus with magicgui, it's best (but not required) to use - Enums. Here we make an Enum class for all of the image math operations we want to - allow. - """ - - add = numpy.add - subtract = numpy.subtract - multiply = numpy.multiply - divide = numpy.divide - - -with gui_qt(): - # create a viewer and add a couple image layers - viewer = Viewer() - viewer.add_image(numpy.random.rand(20, 20), name="Layer 1") - viewer.add_image(numpy.random.rand(20, 20), name="Layer 2") - - # use the magic decorator! This takes a function, generates a custom Widget class - # using the function signature, and adds that class as an attribute named "Gui" on - # the function. - @magicgui(call_button="execute") - def image_arithmetic(layerA: Image, operation: Operation, layerB: Image) -> Image: - """Add, subtracts, multiplies, or divides to image layers with equal shape.""" - return operation.value(layerA.data, layerB.data) - - # Gui() is DEPRECATED - # you should now just add the decorated function directly: - # viewer.window.add_dock_widget(image_arithmetic) - gui = image_arithmetic.Gui() - viewer.window.add_dock_widget(gui.native) - # NOTE: gui.native will not be necessary after - # https://github.com/napari/napari/pull/1994 - - # Use `reset_choices` instead now: - # viewer.layers.events.inserted.connect(image_arithmetic.reset_choices) - # viewer.layers.events.removed.connect(image_arithmetic.reset_choices) - viewer.layers.events.inserted.connect(gui.refresh_choices) - viewer.layers.events.removed.connect(gui.refresh_choices) diff --git a/examples/OLD_napari_param_sweep.py b/examples/OLD_napari_param_sweep.py deleted file mode 100644 index 003449dee..000000000 --- a/examples/OLD_napari_param_sweep.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -!!!!!!!!!!!!!!!!!!!!!!!!!!! -DEPRECATED! DON'T USE THIS -!!!!!!!!!!!!!!!!!!!!!!!!!!! - -This example is just here for aiding in migration to v0.2.0. -see examples/napari_param_sweep.py instead - -""" -import napari -import skimage.data -import skimage.filters -from napari.layers import Image - -from magicgui import magicgui - -# REMOVED! use string 'FloatSlider' instead -from magicgui._qt.widgets import QDoubleSlider - -with napari.gui_qt(): - # create a viewer and add some images - viewer = napari.Viewer() - viewer.add_image(skimage.data.astronaut().mean(-1), name="astronaut") - viewer.add_image(skimage.data.grass().astype("float"), name="grass") - - @magicgui( - auto_call=True, - # "fixedWidth" is qt specific and no longer works - # this will eventually raise an exception - sigma={"widget_type": QDoubleSlider, "max": 6, "fixedWidth": 400}, - mode={"choices": ["reflect", "constant", "nearest", "mirror", "wrap"]}, - ) - def gaussian_blur(layer: Image, sigma: float = 1.0, mode="nearest") -> Image: - """Apply a gaussian blur to ``layer``.""" - if layer: - return skimage.filters.gaussian(layer.data, sigma=sigma, mode=mode) - - # DEPRECATED: you no longer should use Gui()... - # just use `gaussian_blur` directly (it's already a magicgui widget) - gui = gaussian_blur.Gui() - - # should now just be viewer.window.add_dock_widget(gaussian_blur) - viewer.window.add_dock_widget(gui) - - # Should now be: viewer.layers.events.changed.connect(gaussian_blur.reset_choices) - viewer.layers.events.changed.connect(lambda x: gui.refresh_choices("layer")) diff --git a/examples/OLD_snells_law.py b/examples/OLD_snells_law.py deleted file mode 100644 index d87bc94c6..000000000 --- a/examples/OLD_snells_law.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -!!!!!!!!!!!!!!!!!!!!!!!!!!! -DEPRECATED! DON'T USE THIS -!!!!!!!!!!!!!!!!!!!!!!!!!!! - -This example is just here for aiding in migration to v0.2.0. -see examples/snells_law.py instead - -""" - -import math -from enum import Enum - -from magicgui import event_loop, magicgui - - -# dropdown boxes are best made by creating an enum -class Medium(Enum): - """Enum for various media and their refractive indices.""" - - Glass = 1.520 - Oil = 1.515 - Water = 1.333 - Air = 1.0003 - - -@magicgui(call_button="calculate", result_widget=True) -def snells_law(aoi=30.0, n1=Medium.Glass, n2=Medium.Water, degrees=True): - """Calculate the angle of refraction given two media and an AOI.""" - if degrees: - aoi = math.radians(aoi) - try: - n1 = n1.value - n2 = n2.value - result = math.asin(n1 * math.sin(aoi) / n2) - return round(math.degrees(result) if degrees else result, 2) - except ValueError: # math domain error - return "TIR!" - - -with event_loop(): - - # snells_law is *already* a gui in magicgui >= 0.2.0 - gui = snells_law.Gui(show=True) # Gui() is deprecated - - # this syntax is deprecated, use snells_law.n1.changed.conect... - gui.n1_changed.connect(print) - - # we can connect a callback function to the __call__ event on the function - gui.called.connect(lambda e: print("result is", e.value)) diff --git a/magicgui/widgets/_bases/categorical_widget.py b/magicgui/widgets/_bases/categorical_widget.py index 9b8681982..fbd87dd74 100644 --- a/magicgui/widgets/_bases/categorical_widget.py +++ b/magicgui/widgets/_bases/categorical_widget.py @@ -1,5 +1,3 @@ -import inspect -import warnings from enum import EnumMeta from typing import Any, Callable @@ -103,26 +101,8 @@ def choices(self, choices: ChoicesType): _choices = choices["choices"] str_func = choices["key"] elif not isinstance(choices, EnumMeta) and callable(choices): - try: - _choices = choices(self) - except TypeError: - - n_params = len(inspect.signature(choices).parameters) - if n_params > 1: - warnings.warn( - "\n\nAs of magicgui 0.2.0, when providing a callable to " - "`choices`, the\ncallable may accept only a single positional " - "argument (which will\nbe an instance of " - "`magicgui.widgets._bases.CategoricalWidget`),\nand must " - "return an iterable (the choices to show).\nFunction " - f"'{choices.__module__}.{choices.__name__}' accepts {n_params} " - "arguments.\nIn the future, this will raise an exception.\n", - FutureWarning, - ) - # pre 0.2.0 API - _choices = choices(self.native, self.annotation) # type: ignore - else: - raise + _choices = choices(self) + else: _choices = choices if not all(isinstance(i, tuple) and len(i) == 2 for i in _choices): diff --git a/magicgui/widgets/_bases/container_widget.py b/magicgui/widgets/_bases/container_widget.py index 86d54f07c..c1d77ffaf 100644 --- a/magicgui/widgets/_bases/container_widget.py +++ b/magicgui/widgets/_bases/container_widget.py @@ -1,7 +1,6 @@ from __future__ import annotations import inspect -import warnings from typing import ( TYPE_CHECKING, Any, @@ -254,15 +253,6 @@ def reset_choices(self, event=None): if hasattr(widget, "reset_choices"): widget.reset_choices() # type: ignore - def refresh_choices(self, event=None): - """Alias for reset_choices [DEPRECATED: use reset_choices].""" - warnings.warn( - "\n`ContainerWidget.refresh_choices` is deprecated and will be removed in a" - " future version, please use `ContainerWidget.reset_choices` instead.", - FutureWarning, - ) - return self.reset_choices(event) - @property def __signature__(self) -> MagicSignature: """Return a MagicSignature object representing the current state of the gui.""" diff --git a/magicgui/widgets/_bases/widget.py b/magicgui/widgets/_bases/widget.py index 56ba244be..8271dc8f3 100644 --- a/magicgui/widgets/_bases/widget.py +++ b/magicgui/widgets/_bases/widget.py @@ -1,7 +1,6 @@ from __future__ import annotations import inspect -import warnings from contextlib import contextmanager from typing import TYPE_CHECKING, Any, ForwardRef, Optional, Type, Union @@ -63,11 +62,9 @@ def __init__( # for ipywidgets API compatibility label = label or extra.pop("description", None) if extra: - warnings.warn( - f"\n\n{self.__class__.__name__}.__init__() got unexpected " - f"keyword arguments {set(extra)!r}.\n" - "In the future this will raise an exception\n", - FutureWarning, + raise TypeError( + f"{type(self).__name__} got an unexpected " + f"keyword argument: {', '.join(extra)}" ) _prot = self.__class__.__annotations__["_widget"] diff --git a/magicgui/widgets/_function_gui.py b/magicgui/widgets/_function_gui.py index a6ada09dd..e7c94ba41 100644 --- a/magicgui/widgets/_function_gui.py +++ b/magicgui/widgets/_function_gui.py @@ -6,7 +6,6 @@ import inspect import re -import warnings from collections import deque from contextlib import contextmanager from types import FunctionType @@ -198,18 +197,6 @@ def reset_call_count(self) -> None: """Reset the call count to 0.""" self._call_count = 0 - def __getattr__(self, value): - """Catch deprecated _name_changed attribute.""" - if value.endswith("_changed"): - widget_name = value.replace("_changed", "") - warnings.warn( - "\nThe `_changed` signal has been removed in magicgui 0.2.0.\n" - f"Use 'widget.{widget_name}.changed' instead of 'widget.{value}'", - FutureWarning, - ) - return getattr(self, widget_name).changed - return super().__getattr__(value) - # def __delitem__(self, key: Union[int, slice]): # """Delete a widget by integer or slice index.""" # raise AttributeError("can't delete items from a FunctionGui") @@ -340,20 +327,6 @@ def __set__(self, obj, value): """Prevent setting a magicgui attribute.""" raise AttributeError("Can't set magicgui attribute") - def Gui(self, show=False): - """Create a widget instance [DEPRECATED].""" - warnings.warn( - "\n\nCreating a widget instance with `my_function.Gui()` is deprecated,\n" - "the magicgui decorator now returns a widget instance directly, so you\n" - "should simply use the function itself as a magicgui widget, or call\n" - "`my_function.show(run=True)` to run the application.\n" - "In a future version, the `Gui` attribute will be removed.\n", - FutureWarning, - ) - if show: - self.show() - return self - class MainFunctionGui(FunctionGui[_R], MainWindow): """Container of widgets as a Main Application Window.""" diff --git a/tests/test_docs.py b/tests/test_docs.py index e9ffa6b2c..ce14419f2 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -27,11 +27,11 @@ def test_doc_code_cells(fname, globalns=globals()): if "warns" in header.group(): with pytest.warns(None): exec(cell, globalns) - continue + continue if "raises-exception" in header.group(): with pytest.raises(Exception): exec(cell, globalns) - continue + continue exec(cell, globalns) diff --git a/tests/test_widgets.py b/tests/test_widgets.py index 2f56da2c7..38417aec5 100644 --- a/tests/test_widgets.py +++ b/tests/test_widgets.py @@ -92,11 +92,11 @@ def test_custom_widget_fails(): assert "Missing methods: {'_mgui_set_tooltip'}" in str(err) -def test_extra_kwargs_warn(): +def test_extra_kwargs_error(): """Test that unrecognized kwargs gives a FutureWarning.""" - with pytest.warns(FutureWarning) as wrn: + with pytest.raises(TypeError) as wrn: widgets.Label(unknown_kwarg="hi") - assert "unexpected keyword arguments" in str(wrn[0].message) + assert "unexpected keyword argument" in str(wrn) def test_autocall_no_runtime_error():