Repository: biolab/orange3

Issue:
"CN2Classifier object has no attribute params" shows if I press "report" menu of an OWRuleViewer
Here is my environment:
Python 3.9
PyQt5
Orange3

here is my code, you can run this code directly




```from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

import Orange
from Orange.widgets.visualize.owruleviewer import OWRuleViewer
from Orange.classification import CN2Learner



class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1200, 800)
        self.MainWindow = MainWindow

        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.pushButton_showOrange = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_showOrange.setObjectName("pushButton_showOrange")
        self.horizontalLayout.addWidget(self.pushButton_showOrange)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.pushButton_closeOrange = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_closeOrange.setObjectName("pushButton_closeOrange")
        self.horizontalLayout.addWidget(self.pushButton_closeOrange)
        spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem2)
        self.verticalLayout.addLayout(self.horizontalLayout)
        spacerItem3 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.verticalLayout.addItem(spacerItem3)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem4 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem4)

        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tab_added = QtWidgets.QWidget()
        self.tab_added.setObjectName("tab_added")


        current_verticalLayout = QtWidgets.QVBoxLayout(self.tab_added)
        current_verticalLayout.setObjectName("current_verticalLayout")

        spacerItem2 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        current_verticalLayout.addItem(spacerItem2)


        ###############################Python 3.9 + PyQt5 + Orange 3 ######################################

        data = Orange.data.Table(r"D:\Software\Orange3\Orange\Lib\site-packages\Orange\datasets\heart_disease.tab")
        learner = Orange.classification.CN2Learner()
        model = learner(data)
        model.instances = data

        self.ow = OWRuleViewer()   # 1. create an instance
        self.ow.set_classifier(model)
        self.ow.show()

        ####################################################################################################

        self.ow.setParent(self.tab_added)  # 2. add "ow" to the "tab" of the QTabWidget
        ####################################################################################################


        spacerItem3 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        current_verticalLayout.addItem(spacerItem3)

        current_verticalLayout.addWidget(self.ow)  # 3. add "ow" to the vertical layout
        ####################################################################################################

        self.tabWidget.addTab(self.tab_added, "")

        self.horizontalLayout_2.addWidget(self.tabWidget)

        spacerItem5 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem5)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1200, 23))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.pushButton_closeOrange.clicked.connect(self.close_orange)
        self.pushButton_showOrange.clicked.connect(self.show_orange)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_showOrange.setText(_translate("MainWindow", "Open"))
        self.pushButton_closeOrange.setText(_translate("MainWindow", "Close"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_added), _translate("MainWindow", "tab_added"))

    def close_orange(self):
        self.ow.close()

    def show_orange(self):
        self.ow.show()


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

```


Then, click the "report" at the bottom left of the OWRuleViewer
![1 (1)](https://user-images.githubusercontent.com/28619306/212644758-ec5533d9-fe40-4ff7-b0e9-4b1f102c0eba.png)

then "CN2Classifier object has no attribute params" shows
![1 (2)](https://user-images.githubusercontent.com/28619306/212644802-5e283358-0810-4b06-b244-4b03cb3a5898.png)

but, if I comment line 177 in Python\Lib\site-packages\Orange\widgets\visualize\owruleviewer.py as below
![1 (3)](https://user-images.githubusercontent.com/28619306/212644830-a8d0ef0b-e13e-41f4-a9ca-e80818191f95.png)

```
def send_report(self):
	if self.classifier is not None:
		self. report_domain("Data domain", self.classifier.original_domain)
		#self. report_items("Rule induction algorithm", self.classifier.params)
		self. report_table("Induced rules", self.view)
```

then error will not occur and it works correctly:
![1 (4)](https://user-images.githubusercontent.com/28619306/212644652-59825add-1d0d-4bbf-8cf8-128da2fc39dd.png)

so, is this a bug? or do I forget a neccesary step (call some method or set some attribute?) after creating an instance of OWRuleViewer?

```
        data = Orange.data.Table(r"D:\Software\Orange3\Orange\Lib\site-packages\Orange\datasets\heart_disease.tab")
        learner = Orange.classification.CN2Learner()
        model = learner(data)
        model.instances = data

        self.ow = OWRuleViewer()   # 1. create an instance
        self.ow.set_classifier(model)
        self.ow.show()
```







Discussion:

Resolving patch:
diff --git a/Orange/widgets/visualize/owruleviewer.py b/Orange/widgets/visualize/owruleviewer.py
--- a/Orange/widgets/visualize/owruleviewer.py
+++ b/Orange/widgets/visualize/owruleviewer.py
@@ -174,7 +174,6 @@ def commit(self):
     def send_report(self):
         if self.classifier is not None:
             self.report_domain("Data domain", self.classifier.original_domain)
-            self.report_items("Rule induction algorithm", self.classifier.params)
             self.report_table("Induced rules", self.view)
 
     def sizeHint(self):


Test patch: