Giter Club home page Giter Club logo

Comments (13)

irgolic avatar irgolic commented on August 12, 2024

Woah this is really cool. We're thinking of moving core Orange to a task graph system (using dask arrays), so this is right up our alley. Would you be willing to share your code with us? :)

Regarding adding class attributes dynamically, I suggest a metaclass. Make sure the metaclass extends WidgetMetaClass.

from orange-widget-base.

janezd avatar janezd commented on August 12, 2024

See #144. You can derive from any class, for as long as the ancestor (that is, your class containing the boiler code) is marked with openclass=True.

Meta classes are of course an option, too, but I'd strongly encourage going with normal subclassing.

While I was writing this, @irgolic suggested meta classes. If all your widgets have the same inputs and outputs, you don't need meta classes. If they are different, this would be parametrized meta class. Go for it, if you really must. :)

from orange-widget-base.

irgolic avatar irgolic commented on August 12, 2024

Judging only by the code snippet you posted here, I think I may've solved this exact problem for orange3-pandas, wherein widget UIs are generated from pandas docstrings/signatures.

It's not quite ready/released yet, but if you say hi on Discord, I can share.

from orange-widget-base.

woutdenolf avatar woutdenolf commented on August 12, 2024

@irgolic We don't even have proper projects yet but you could already have a look at this:
https://gitlab.esrf.fr/denolf/workflow_concepts

It's an attempt at finding the optimal ECO system of projects suitable for workflows at the ESRF. Orange3 would be part of that.

We will probably have one core project for representing task graphs (persistent and at runtime):
https://gitlab.esrf.fr/denolf/workflow_concepts/-/tree/master/esrftaskgraph

And then bindings for task schedulers and graph design GUIs. This is what we have so far for Orange:
https://gitlab.esrf.fr/denolf/workflow_concepts/-/tree/master/esrf2orange3

And this is the binding for dask:
https://gitlab.esrf.fr/denolf/workflow_concepts/-/tree/master/esrf2dask

from orange-widget-base.

irgolic avatar irgolic commented on August 12, 2024

I don't think I can access your internal gitlab.

Screenshot 2021-03-15 at 15 47 21

from orange-widget-base.

woutdenolf avatar woutdenolf commented on August 12, 2024

Ah sorry, it was not even a public project yet, that's how recent this is ;-). Try again.

from orange-widget-base.

woutdenolf avatar woutdenolf commented on August 12, 2024

I tried with a metaclass and a subclass but I need to do this

class WidgetMetaClass(type(QDialog)):
    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
         # >>> HERE I NEED TO ADD inputs, outputs and settings
        cls.convert_signals()
        cls.settingsHandler = \
            SettingsHandler.create(cls, template=cls.settingsHandler)
        return cls

Any suggestions? Of course I could do something dodgy with convert_signals but that might break in the future.

from orange-widget-base.

woutdenolf avatar woutdenolf commented on August 12, 2024

No in fact I cannot even do that because I have no way of passing new arguments.

class ESRFWidgetMetaClass(WidgetMetaClass):
    def __new__(
        metacls,
        name,
        bases,
        attr,
        esrftaskclass=None,
        input_names=None,
        output_names=None,
        **kw
    ):
        if input_names is None:
            input_names = dict()
        if output_names is None:
            output_names = dict()
        prepare_kw = {
            "esrftaskclass": esrftaskclass,
            "inputnamemap": input_names,
            "outputnamemap": output_names,
        }
        # _prepare_owesrfwidgetclass need to access prepare_kw
    return super().__new__(metacls, name, bases, attr, **kw)

    @classmethod
    def convert_signals(cls):
        cls._prepare_owesrfwidgetclass()
        super().convert_signals()

    @classmethod
    def _prepare_owesrfwidgetclass(cls):
          ...

from orange-widget-base.

irgolic avatar irgolic commented on August 12, 2024

You might need to do something funky if you wanted to use the signals syntactic sugar, but if you add to attr (namespace) a list named inputs of (name, type, method_name, flags) tuples, it should be fine.

from orange-widget-base.

woutdenolf avatar woutdenolf commented on August 12, 2024

Ok perfect, I can do what I want now by using WidgetMetaClass and subclassing with openclass=True. Thanks!

from orange-widget-base.

janezd avatar janezd commented on August 12, 2024

I have foreseen that. I wrote that you'll need parametrized meta classes. :)

If all your subclasses have the same inputs and outputs, then add them to your base class, not the meta class. You have an example here: https://github.com/biolab/orange3/blob/master/Orange/widgets/utils/owlearnerwidget.py#L54. This is an open widget class that defines signals, and errors and a part of GUI... Derived classes can add to that. For instance, Logistic regression (https://github.com/biolab/orange3/blob/master/Orange/widgets/model/owlogisticregression.py#L15) adds an additional output and warning, by deriving its output from the inherited class with outputs.

I still don't see why would you need meta classes.

But if you do, you can do two things.

You can add arguments to new, just differently. You can define your meta class exactly as you did above, and then use it like this

class MyWidget(OWBaseWidget, metaclass=ESRFWidgetMetaClass, esrftaskclass=..., input_names=...):
    ...

The arguments to the meta class are given as the arguments to the widget class definition. Incidentally, this is how openclass is implemented in Orange. See https://github.com/biolab/orange-widget-base/blob/master/orangewidget/widget.py#L96: openclass is an extra argument to __new__ and it's value (which is False be default) is overridden in, for example, the code I linked to above. https://github.com/biolab/orange3/blob/master/Orange/widgets/utils/owlearnerwidget.py#L54.

The other way is totally fancy. Parametrizing meta classes via closures.

def my_metaclass(esrftaskclass=None, input_names=None, output_names=None):
    class ESRFWidgetMetaClass(WidgetMetaClass):
        def __new__(metacls, name, bases):
            ...

    return ESRFWidgetMetaClass


class MyWidget(OWBaseWidget, metaclass=my_metaclass(my_specific_task_class, my_input_names)):
    ....

In this way, every widget will have his specific meta class.

from orange-widget-base.

janezd avatar janezd commented on August 12, 2024

Ok perfect, I can do what I want now by using WidgetMetaClass and subclassing with openclass=True. Thanks!

No, no, don't. Just pass openclass=True to the widget from which you plan to derive other widgets. Check this: https://github.com/biolab/orange3/blob/master/Orange/widgets/data/owpreprocess.py#L1066. This is the widget that preprocessing widgets are derived from.

class OWPreprocess(widget.OWWidget, openclass=True):
    ...

    class Inputs:
        data = Input("Data", Orange.data.Table)

    class Outputs:
        preprocessor = Output("Preprocessor", preprocess.preprocess.Preprocess, dynamic=False)
        preprocessed_data = Output("Preprocessed Data", Orange.data.Table)

    storedsettings = Setting({})
    autocommit = Setting(True)
    PREPROCESSORS = PREPROCESS_ACTIONS
    CONTROLLER = Controller

    ...

from orange-widget-base.

woutdenolf avatar woutdenolf commented on August 12, 2024

Yes I got that. I have one common base widget from which I will be deriving my normal widgets

class OWESRFWidget(OWWidget, metaclass=ESRFWidgetMetaClass, openclass=True):
    ...

class MyWidget1(OWESRFWidget, esrftaskclass=MyClass1):
    ...

class MyWidget2(OWESRFWidget, esrftaskclass=MyClass2):
    ...

ESRFWidgetMetaClass adds inputs, outputs and settings based on the esrftaskclass argument. The classes MyClass1, MyClass2, ... do the actual computations (they also know what the inputs and outputs are). This is how we want to decouple GUI from computation so we can execute task graphs without needing the canvas (or Orange for that matter) by different task schedulers (luigi, dask, ... depending on what kind of distribution we need).

from orange-widget-base.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.