@@ -79,6 +79,14 @@ class Error(OWWidget.Error):
7979 class Warning (OWWidget .Warning ):
8080 outdated_learner = Msg ("Press Apply to submit changes." )
8181
82+ class Information (OWWidget .Information ):
83+ ignored_preprocessors = Msg (
84+ "Ignoring default preprocessing.\n "
85+ "Default preprocessing, such as scaling, one-hot encoding and "
86+ "treatment of missing data, has been replaced with user-specified "
87+ "preprocessors. Problems may occur if these are inadequate "
88+ "for the given data." )
89+
8290 class Inputs :
8391 data = Input ("Data" , Table )
8492 preprocessor = Input ("Preprocessor" , Preprocess )
@@ -90,6 +98,8 @@ class Outputs:
9098
9199 OUTPUT_MODEL_NAME = Outputs .model .name # Attr for backcompat w/ self.send() code
92100
101+ _SEND , _SOFT , _UPDATE = range (3 )
102+
93103 def __init__ (self , preprocessors = None ):
94104 super ().__init__ ()
95105 self .__default_learner_name = ""
@@ -99,6 +109,7 @@ def __init__(self, preprocessors=None):
99109 self .model = None
100110 self .preprocessors = preprocessors
101111 self .outdated_settings = False
112+ self .__apply_level = []
102113
103114 self .setup_layout ()
104115 QTimer .singleShot (0 , getattr (self , "unconditional_apply" , self .apply ))
@@ -144,7 +155,8 @@ def set_default_learner_name(self, name: str) -> None:
144155 @Inputs .preprocessor
145156 def set_preprocessor (self , preprocessor ):
146157 self .preprocessors = preprocessor
147- self .apply ()
158+ # invalidate learner and model, so handleNewSignals will renew them
159+ self .learner = self .model = None
148160
149161 @Inputs .data
150162 @check_sql_input
@@ -164,23 +176,50 @@ def set_data(self, data):
164176 "Select one with the Select Columns widget." )
165177 self .data = None
166178
167- self .update_model ()
179+ # invalidate the model so that handleNewSignals will update it
180+ self .model = None
181+
168182
169183 def apply (self ):
184+ level , self .__apply_level = max (self .__apply_level , default = self ._UPDATE ), []
170185 """Applies learner and sends new model."""
171- self .update_learner ()
172- self .update_model ()
186+ if level == self ._SEND :
187+ self ._send_learner ()
188+ self ._send_model ()
189+ elif level == self ._UPDATE :
190+ self .update_learner ()
191+ self .update_model ()
192+ else :
193+ self .learner or self .update_learner ()
194+ self .model or self .update_model ()
195+
196+ def apply_as (self , level , unconditional = False ):
197+ self .__apply_level .append (level )
198+ if unconditional :
199+ self .unconditional_apply ()
200+ else :
201+ self .apply ()
173202
174203 def update_learner (self ):
175204 self .learner = self .create_learner ()
176205 if self .learner and issubclass (self .LEARNER , Fitter ):
177206 self .learner .use_default_preprocessors = True
178207 if self .learner is not None :
179208 self .learner .name = self .effective_learner_name ()
209+ self ._send_learner ()
210+
211+ def _send_learner (self ):
180212 self .Outputs .learner .send (self .learner )
181213 self .outdated_settings = False
182214 self .Warning .outdated_learner .clear ()
183215
216+ def handleNewSignals (self ):
217+ self .apply_as (self ._SOFT , True )
218+ self .Information .ignored_preprocessors (
219+ shown = not getattr (self .learner , "use_default_preprocessors" , False )
220+ and getattr (self .LEARNER , "preprocessors" , False )
221+ and self .preprocessors is not None )
222+
184223 def show_fitting_failed (self , exc ):
185224 """Show error when fitting fails.
186225 Derived widgets can override this to show more specific messages."""
@@ -197,6 +236,9 @@ def update_model(self):
197236 else :
198237 self .model .name = self .learner_name or self .captionTitle
199238 self .model .instances = self .data
239+ self ._send_model ()
240+
241+ def _send_model (self ):
200242 self .Outputs .model .send (self .model )
201243
202244 def check_data (self ):
@@ -223,15 +265,12 @@ def settings_changed(self, *args, **kwargs):
223265 self .Warning .outdated_learner (shown = not self .auto_apply )
224266 self .apply ()
225267
226- def _change_name (self , instance , output ):
227- if instance :
228- instance .name = self .effective_learner_name ()
229- if self .auto_apply :
230- output .send (instance )
231-
232268 def learner_name_changed (self ):
233- self ._change_name (self .learner , self .Outputs .learner )
234- self ._change_name (self .model , self .Outputs .model )
269+ if self .model is not None :
270+ self .model .name = self .effective_learner_name ()
271+ if self .learner is not None :
272+ self .learner .name = self .effective_learner_name ()
273+ self .apply_as (self ._SEND )
235274
236275 def effective_learner_name (self ):
237276 """Return the effective learner name."""
@@ -272,7 +311,6 @@ def add_main_layout(self):
272311 Override this method for laying out any learner-specific parameter controls.
273312 See setup_layout() method for execution order.
274313 """
275- pass
276314
277315 def add_classification_layout (self , box ):
278316 """Creates layout for classification specific options.
@@ -281,7 +319,6 @@ def add_classification_layout(self, box):
281319 and regression learners require different options.
282320 See `setup_layout()` method for execution order.
283321 """
284- pass
285322
286323 def add_regression_layout (self , box ):
287324 """Creates layout for regression specific options.
@@ -290,7 +327,6 @@ def add_regression_layout(self, box):
290327 and regression learners require different options.
291328 See `setup_layout()` method for execution order.
292329 """
293- pass
294330
295331 def add_learner_name_widget (self ):
296332 self .name_line_edit = gui .lineEdit (
0 commit comments