Skip to content

Commit

Permalink
refactor: repo reorganization and return removed names (#497)
Browse files Browse the repository at this point in the history
* refactor: move type_map and magicgui

* refactor: move image

* refactor: don't write version

* refactor: change name unknown

* refactor: move schema

* fix: replace some missing names

* add back pick_widget_type

* refactor: big name changes

* fix: fix magicclass tests

* omit from coverage
  • Loading branch information
tlambert03 committed Nov 13, 2022
1 parent 3c0c49b commit 9fa5ebe
Show file tree
Hide file tree
Showing 50 changed files with 876 additions and 792 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,4 @@ dmypy.json

.vscode
.DS_Store
magicgui/_version.py
examples/_wip
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ repos:
hooks:
- id: mypy
files: magicgui
exclude: magicgui/_magicgui.py
exclude: magicgui/type_map/_magicgui.py
additional_dependencies:
- numpy
2 changes: 0 additions & 2 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
ignore:
- magicgui/_version.py
coverage:
status:
project:
Expand Down
10 changes: 6 additions & 4 deletions magicgui/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
"""magicgui is a utility for generating a GUI from a python function."""
from importlib.metadata import PackageNotFoundError, version

try:
from ._version import version as __version__
except ImportError:
__version__ = "unknown"
__version__ = version("magicgui")
except PackageNotFoundError: # pragma: no cover
__version__ = "uninstalled"

__author__ = """Talley Lambert"""
__email__ = "talley.lambert@gmail.com"


from ._magicgui import magic_factory, magicgui
from .application import event_loop, use_app
from .type_map import register_type, type_registered
from .type_map._magicgui import magic_factory, magicgui

__all__ = [
"event_loop",
Expand Down
8 changes: 8 additions & 0 deletions magicgui/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,11 @@ def user_cache_dir(
if appname and version:
path = path / version
return path


def safe_issubclass(obj, superclass):
"""Safely check if obj is a subclass of superclass."""
try:
return issubclass(obj, superclass)
except Exception:
return False
2 changes: 1 addition & 1 deletion magicgui/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from magicgui.backends import BACKENDS

if TYPE_CHECKING:
from magicgui.widgets._protocols import BaseApplicationBackend
from magicgui.widgets.protocols import BaseApplicationBackend

DEFAULT_BACKEND = "qt"
APPLICATION_NAME = "magicgui"
Expand Down
2 changes: 1 addition & 1 deletion magicgui/backends/_ipynb/application.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from magicgui.widgets._protocols import BaseApplicationBackend
from magicgui.widgets.protocols import BaseApplicationBackend


class ApplicationBackend(BaseApplicationBackend):
Expand Down
20 changes: 9 additions & 11 deletions magicgui/backends/_ipynb/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"Please run `pip install ipywidgets`"
) from e

from magicgui.widgets import _protocols
from magicgui.widgets._bases import Widget
from magicgui.widgets import protocols
from magicgui.widgets.bases import Widget


def _pxstr2int(pxstr: Union[int, str]) -> int:
Expand All @@ -25,7 +25,7 @@ def _int2pxstr(pxint: Union[int, str]) -> str:
return f"{pxint}px" if isinstance(pxint, int) else pxint


class _IPyWidget(_protocols.WidgetProtocol):
class _IPyWidget(protocols.WidgetProtocol):
_ipywidget: ipywdg.Widget

def __init__(
Expand Down Expand Up @@ -145,7 +145,7 @@ def _mgui_bind_change_callback(self, callback: Callable):
pass


class _IPyValueWidget(_IPyWidget, _protocols.ValueWidgetProtocol):
class _IPyValueWidget(_IPyWidget, protocols.ValueWidgetProtocol):
def _mgui_get_value(self) -> float:
return self._ipywidget.value

Expand All @@ -164,7 +164,7 @@ def _mgui_set_value(self, value) -> None:
super()._mgui_set_value(str(value))


class _IPyRangedWidget(_IPyValueWidget, _protocols.RangedWidgetProtocol):
class _IPyRangedWidget(_IPyValueWidget, protocols.RangedWidgetProtocol):
def _mgui_get_min(self) -> float:
return self._ipywidget.min

Expand Down Expand Up @@ -192,7 +192,7 @@ def _mgui_set_adaptive_step(self, value: bool):
# raise NotImplementedError('adaptive step not implemented for ipywidgets')


class _IPySupportsOrientation(_protocols.SupportsOrientation):
class _IPySupportsOrientation(protocols.SupportsOrientation):
_ipywidget: ipywdg.Widget

def _mgui_set_orientation(self, value) -> None:
Expand All @@ -202,7 +202,7 @@ def _mgui_get_orientation(self) -> str:
return self._ipywidget.orientation


class _IPySupportsChoices(_protocols.SupportsChoices):
class _IPySupportsChoices(protocols.SupportsChoices):
_ipywidget: ipywdg.Widget

def _mgui_get_choices(self) -> Tuple[Tuple[str, Any]]:
Expand Down Expand Up @@ -243,7 +243,7 @@ def _mgui_set_choice(self, choice_name: str, data: Any) -> None:
self._ipywidget.options = self._ipywidget.options + ((choice_name, data),)


class _IPySupportsText(_protocols.SupportsText):
class _IPySupportsText(protocols.SupportsText):
"""Widget that have text (in addition to value)... like buttons."""

_ipywidget: ipywdg.Widget
Expand Down Expand Up @@ -367,9 +367,7 @@ class Select(_IPyCategoricalWidget):
# CONTAINER ----------------------------------------------------------------------


class Container(
_IPyWidget, _protocols.ContainerProtocol, _protocols.SupportsOrientation
):
class Container(_IPyWidget, protocols.ContainerProtocol, protocols.SupportsOrientation):
def __init__(self, layout="horizontal", scrollable: bool = False, **kwargs):
wdg_class = ipywidgets.VBox if layout == "vertical" else ipywidgets.HBox
super().__init__(wdg_class, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion magicgui/backends/_qtpy/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from qtpy.QtWidgets import QApplication

from magicgui.application import APPLICATION_NAME
from magicgui.widgets._protocols import BaseApplicationBackend
from magicgui.widgets.protocols import BaseApplicationBackend


class ApplicationBackend(BaseApplicationBackend):
Expand Down
29 changes: 14 additions & 15 deletions magicgui/backends/_qtpy/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
)

from magicgui.types import FileDialogMode
from magicgui.widgets import _protocols
from magicgui.widgets._bases import Widget
from magicgui.widgets import Widget, protocols


@contextmanager
Expand All @@ -51,7 +50,7 @@ def eventFilter(self, obj: QObject, event: QEvent):
return False


class QBaseWidget(_protocols.WidgetProtocol):
class QBaseWidget(protocols.WidgetProtocol):
"""Implements show/hide/native."""

_qwidget: QtW.QWidget
Expand Down Expand Up @@ -174,7 +173,7 @@ def _mgui_render(self):
return arr[:, :, [2, 1, 0, 3]]


class QBaseValueWidget(QBaseWidget, _protocols.ValueWidgetProtocol):
class QBaseValueWidget(QBaseWidget, protocols.ValueWidgetProtocol):
"""Implements get/set/bind_change."""

def __init__(
Expand Down Expand Up @@ -305,7 +304,7 @@ def _post_get_hook(self, value):
return literal_eval(value)


class TextEdit(QBaseStringWidget, _protocols.SupportsReadOnly):
class TextEdit(QBaseStringWidget, protocols.SupportsReadOnly):
def __init__(self, **kwargs):
super().__init__(
QtW.QTextEdit, "toPlainText", "setText", "textChanged", **kwargs
Expand All @@ -321,7 +320,7 @@ def _mgui_get_read_only(self) -> bool:
# NUMBERS


class QBaseRangedWidget(QBaseValueWidget, _protocols.RangedWidgetProtocol):
class QBaseRangedWidget(QBaseValueWidget, protocols.RangedWidgetProtocol):
"""Provides min/max/step implementations."""

_qwidget: QtW.QDoubleSpinBox | QtW.QSpinBox | QtW.QAbstractSlider
Expand Down Expand Up @@ -382,7 +381,7 @@ def _update_precision(self, **kwargs):
# BUTTONS


class QBaseButtonWidget(QBaseValueWidget, _protocols.SupportsText):
class QBaseButtonWidget(QBaseValueWidget, protocols.SupportsText):
_qwidget: QtW.QCheckBox | QtW.QPushButton | QtW.QRadioButton | QtW.QToolButton

def __init__(self, qwidg, **kwargs):
Expand Down Expand Up @@ -422,7 +421,7 @@ def __init__(self, **kwargs):


class Container(
QBaseWidget, _protocols.ContainerProtocol, _protocols.SupportsOrientation
QBaseWidget, protocols.ContainerProtocol, protocols.SupportsOrientation
):
def __init__(self, layout="vertical", scrollable: bool = False, **kwargs):
QBaseWidget.__init__(self, QtW.QWidget, **kwargs)
Expand Down Expand Up @@ -554,7 +553,7 @@ def _mgui_set_step(self, value: float):
self._qwidget.setSingleStep(value)


class _Slider(QBaseRangedWidget, _protocols.SupportsOrientation):
class _Slider(QBaseRangedWidget, protocols.SupportsOrientation):
_qwidget: QtW.QSlider

def __init__(
Expand Down Expand Up @@ -791,7 +790,7 @@ def _mgui_set_readout_visibility(self, value: bool):
self._qwidget.setTextVisible(value)


class ComboBox(QBaseValueWidget, _protocols.CategoricalWidgetProtocol):
class ComboBox(QBaseValueWidget, protocols.CategoricalWidgetProtocol):
_qwidget: QtW.QComboBox

def __init__(self, **kwargs):
Expand Down Expand Up @@ -880,7 +879,7 @@ def _mgui_get_choices(self) -> tuple[tuple[str, Any], ...]:
)


class Select(QBaseValueWidget, _protocols.CategoricalWidgetProtocol):
class Select(QBaseValueWidget, protocols.CategoricalWidgetProtocol):
_qwidget: QtW.QListWidget

def __init__(self, **kwargs):
Expand Down Expand Up @@ -976,8 +975,8 @@ def _mgui_get_choices(self) -> tuple[tuple[str, Any], ...]:

class RadioButtons(
QBaseValueWidget,
_protocols.CategoricalWidgetProtocol,
_protocols.SupportsOrientation,
protocols.CategoricalWidgetProtocol,
protocols.SupportsOrientation,
):
_qwidget: QtW.QGroupBox

Expand Down Expand Up @@ -1114,7 +1113,7 @@ def _mgui_get_value(self):
return self._qwidget.time().toPyTime()


class Dialog(QBaseWidget, _protocols.ContainerProtocol):
class Dialog(QBaseWidget, protocols.ContainerProtocol):
def __init__(self, layout="vertical", scrollable: bool = False, **kwargs):
QBaseWidget.__init__(self, QtW.QDialog, **kwargs)
if layout == "horizontal":
Expand Down Expand Up @@ -1293,7 +1292,7 @@ def keyPressEvent(self, e: QKeyEvent):
return super().keyPressEvent(e)


class Table(QBaseWidget, _protocols.TableWidgetProtocol):
class Table(QBaseWidget, protocols.TableWidgetProtocol):
_qwidget: _QTableExtended
_DATA_ROLE: int = 255
_EDITABLE = QtW.QTableWidget.EditKeyPressed | QtW.QTableWidget.DoubleClicked
Expand Down
1 change: 1 addition & 0 deletions magicgui/schema/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Module for defining the schema of a magicgui widget."""
8 changes: 4 additions & 4 deletions magicgui/_ui_field.py → magicgui/schema/_ui_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from typing_extensions import Annotated, TypeGuard, get_args, get_origin

from .types import JsonStringFormats, Undefined
from magicgui.types import JsonStringFormats, Undefined

if TYPE_CHECKING:
from typing import Mapping, Protocol
Expand All @@ -33,7 +33,7 @@
from attrs import Attribute
from pydantic.fields import ModelField

from .widgets._bases import ContainerWidget, ValueWidget
from magicgui.widgets.bases import ContainerWidget, ValueWidget

class HasAttrs(Protocol):
"""Protocol for objects that have an ``attrs`` attribute."""
Expand Down Expand Up @@ -353,7 +353,7 @@ def resolved_type(self) -> Any:
Note that this will also return the origin type for Annotated types.
"""
from ._type_resolution import _try_cached_resolve
from magicgui._type_resolution import _try_cached_resolve

return _try_cached_resolve(self.type)

Expand Down Expand Up @@ -392,7 +392,7 @@ def parse_annotated(self) -> UiField[T]:

def create_widget(self, value=Undefined) -> ValueWidget:
"""Create a new Widget for this field."""
from .type_map import get_widget_class
from magicgui.type_map import get_widget_class

# TODO: this should be cached in some way
# Map uifield names to widget kwargs
Expand Down
5 changes: 2 additions & 3 deletions magicgui/signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
from magicgui.types import Undefined

if TYPE_CHECKING:
from magicgui.widgets import Container
from magicgui.widgets._bases import Widget
from magicgui.widgets import Container, Widget

TZ_EMPTY = "__no__default__"

Expand Down Expand Up @@ -136,7 +135,7 @@ def __str__(self) -> str:

def to_widget(self, app: AppRef = None) -> Widget:
"""Create and return a widget for this object."""
from magicgui.widgets._bases import create_widget
from magicgui.widgets import create_widget

value = Undefined if self.default in (self.empty, TZ_EMPTY) else self.default
annotation, options = split_annotated_type(self.annotation)
Expand Down
13 changes: 4 additions & 9 deletions magicgui/tqdm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""A wrapper around the tqdm.tqdm iterator that adds a ProgressBar to a magicgui."""
import contextlib
import inspect
from typing import Iterable, Optional, cast

Expand All @@ -12,7 +13,7 @@
f"{e}. To use magicgui with tqdm please `pip install tqdm`, "
"or use the tqdm extra: `pip install magicgui[tqdm]`"
)
raise type(e)(msg)
raise type(e)(msg) from e


def _find_calling_function_gui(max_depth=6) -> Optional[FunctionGui]:
Expand All @@ -26,10 +27,7 @@ def _find_calling_function_gui(max_depth=6) -> Optional[FunctionGui]:
# have the ``FunctionGui`` instance as ``self`` in its locals namespace.
if finfo.function == "__call__" and finfo.filename.endswith("function_gui.py"):
obj = finfo.frame.f_locals.get("self")
if isinstance(obj, FunctionGui):
return obj
return None # pragma: no cover

return obj if isinstance(obj, FunctionGui) else None
return None


Expand Down Expand Up @@ -149,11 +147,8 @@ def close(self) -> None:

# remove from tqdm instance set
with self._lock:
try:
with contextlib.suppress(KeyError):
self._instances.remove(self)
except KeyError: # pragma: no cover
pass

if not self.leave:
self._app.process_events()
self.progressbar.hide()
Expand Down
Loading

0 comments on commit 9fa5ebe

Please sign in to comment.