Skip to content

Commit

Permalink
Make widget classes final unless declared open
Browse files Browse the repository at this point in the history
  • Loading branch information
janezd committed Mar 8, 2019
1 parent d3b5f3c commit 86f4a5d
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 6 deletions.
6 changes: 3 additions & 3 deletions Orange/widgets/utils/owlearnerwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class OWBaseLearnerMeta(WidgetMetaClass):
its own Outputs class with output that match the corresponding
learner.
"""
def __new__(cls, name, bases, attributes):
def __new__(cls, name, bases, attributes, **kwargs):
def abstract_widget():
return not attributes.get("name")

Expand All @@ -35,7 +35,7 @@ def copy_outputs(template):
setattr(result, name, deepcopy(signal))
return result

obj = super().__new__(cls, name, bases, attributes)
obj = super().__new__(cls, name, bases, attributes, **kwargs)
if abstract_widget():
return obj

Expand All @@ -51,7 +51,7 @@ def copy_outputs(template):
return obj


class OWBaseLearner(OWWidget, metaclass=OWBaseLearnerMeta):
class OWBaseLearner(OWWidget, metaclass=OWBaseLearnerMeta, openclass=True):
"""Abstract widget for classification/regression learners.
Notes
Expand Down
25 changes: 22 additions & 3 deletions Orange/widgets/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,29 @@ class WidgetMetaClass(type(QDialog)):

#noinspection PyMethodParameters
# pylint: disable=bad-classmethod-argument
def __new__(mcs, name, bases, kwargs):
cls = super().__new__(mcs, name, bases, kwargs)
def __new__(mcs, name, bases, namespace, openclass=False, **kwargs):
cls = super().__new__(mcs, name, bases, namespace, **kwargs)
if not cls.name: # not a widget
return cls
cls.convert_signals()
cls.settingsHandler = \
SettingsHandler.create(cls, template=cls.settingsHandler)
return cls

@classmethod
# pylint: disable=bad-classmethod-argument
def __prepare__(mcs, name, bases, metaclass=None, openclass=False,
**kwargs):
namespace = super().__prepare__(mcs, name, bases, metaclass, **kwargs)
if not openclass:
namespace["_final_class"] = True
return namespace


# pylint: disable=too-many-instance-attributes
class OWWidget(QDialog, OWComponent, Report, ProgressBarMixin,
WidgetMessagesMixin, WidgetSignalsMixin,
metaclass=WidgetMetaClass):
metaclass=WidgetMetaClass, openclass=True):
"""Base widget class"""

# Global widget count
Expand Down Expand Up @@ -263,6 +272,16 @@ def __new__(cls, *args, captionTitle=None, **kwargs):
def __init__(self, *args, **kwargs):
"""__init__s are called in __new__; don't call them from here"""

def __init_subclass__(cls, **_):
for base in cls.__bases__:
if hasattr(base, "_final_class"):
warnings.warn(
"subclassing of widget classes is deprecated and will be "
"disabled in the future.\n"
f"Extract code from {base.__name__} or explicitly open it.",
RuntimeWarning)
# raise TypeError(f"class {base.__name__} cannot be subclassed")

@classmethod
def get_widget_description(cls):
if not cls.name:
Expand Down

0 comments on commit 86f4a5d

Please sign in to comment.