Commits

Miha Stajdohar committed 3152b8f Merge

Merge.

Comments (0)

Files changed (54)

Orange/OrangeCanvas/application/canvasmain.py

                     icon=canvas_icons("Open.svg")
                     )
 
+        self.open_and_freeze_action = \
+            QAction(self.tr("Open and Freeze"), self,
+                    objectName="action-open-and-freeze",
+                    toolTip=self.tr("Open a new scheme and freeze signal "
+                                    "propagation."),
+                    triggered=self.open_and_freeze_scheme
+                    )
+
         self.save_action = \
             QAction(self.tr("Save"), self,
                     objectName="action-save",
         file_menu = QMenu(self.tr("&File"), menu_bar)
         file_menu.addAction(self.new_action)
         file_menu.addAction(self.open_action)
+        file_menu.addAction(self.open_and_freeze_action)
         file_menu.addAction(self.reload_last_action)
 
         # File -> Open Recent submenu
         else:
             return QDialog.Rejected
 
+    def open_and_freeze_scheme(self):
+        """
+        Open a new scheme and freeze signal propagation. Return
+        QDialog.Rejected if the user canceled the operation and
+        QDialog.Accepted otherwise.
+
+        """
+        frozen = self.freeze_action.isChecked()
+        if not frozen:
+            self.freeze_action.trigger()
+
+        state = self.open_scheme()
+        if state == QDialog.Rejected:
+            # If the action was rejected restore the original frozen state
+            if not frozen:
+                self.freeze_action.trigger()
+        return state
+
     def open_scheme_file(self, filename):
         """
         Open and load a scheme file.

Orange/OrangeCanvas/main.py

             else:
                 log.info("%r style sheet not found.", stylesheet)
 
-    if stylesheet_string is not None:
-        app.setStyleSheet(stylesheet_string)
-
     # Add the default canvas_icons search path
     dirpath = os.path.abspath(os.path.dirname(OrangeCanvas.__file__))
     QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons"))
 
     canvas_window = CanvasMainWindow()
 
+    if stylesheet_string is not None:
+        canvas_window.setStyleSheet(stylesheet_string)
+
     if not options.force_discovery:
         reg_cache = cache.registry_cache()
     else:

Orange/OrangeWidgets/OWBaseWidget.py

 # Orange Widget
 # A General Orange Widget, from which all the Orange Widgets are derived
 #
+import warnings
+
 from Orange.utils import environ
 from Orange.orng.orngEnviron import directoryNames as old_directory_names
 from PyQt4.QtCore import *
         self.asyncBlock = False
         self.__wasShown = False
         self.__progressBarValue = -1
+        self.__progressState = 0
 
     # uncomment this when you need to see which events occured
     """
         self.setWindowTitle(self.captionTitle + " (0% complete)")
         if self.progressBarHandler:
             self.progressBarHandler(self, 0)
-        self.processingStateChanged.emit(1)
+
+        if self.__progressState != 1:
+            self.__progressState = 1
+            self.processingStateChanged.emit(1)
 
     def progressBarSet(self, value, processEventsFlags=QEventLoop.AllEvents):
         """
         """
         old = self.__progressBarValue
         if value > 0:
+            if self.__progressState != 1:
+                warnings.warn("progressBarSet() called without a "
+                              "preceding progressBarInit()",
+                              stacklevel=2)
+                self.__progressState = 1
+                self.processingStateChanged.emit(1)
+
             self.__progressBarValue = value
             usedTime = max(1, time.time() - self.startTime)
             totalTime = (100.0 * usedTime) / float(value)
         self.setWindowTitle(self.captionTitle)
         if self.progressBarHandler:
             self.progressBarHandler(self, 101)
-        self.processingStateChanged.emit(0)
+
+        if self.__progressState != 0:
+            self.__progressState = 0
+            self.processingStateChanged.emit(0)
 
     # handler must be a function, that receives 2 arguments. First is the widget instance, the second is the value between -1 and 101
     def setProgressBarHandler(self, handler):

Orange/data/discretization.py

 import Orange
 
-from Orange.core import\
-    EquiNDiscretization as EqualFreq,\
-    EquiDistDiscretization as EqualWidth,\
-    EntropyDiscretization as Entropy,\
-    BiModalDiscretization as BiModal,\
-    Preprocessor_discretize
-
+from Orange.core import Preprocessor_discretize
 
 class DiscretizeTable(object):
     """Discretizes all continuous features of the data table.
 
     """
     def __new__(cls, data=None, features=None, discretize_class=False,
-                method=EqualFreq(n=3), clean=True):
+                method=Orange.feature.discretization.EqualFreq(n=3), clean=True):
         if data is None:
             self = object.__new__(cls)
             return self
             return self(data)
 
     def __init__(self, features=None, discretize_class=False,
-                 method=EqualFreq(n=3), clean=True):
+                 method=Orange.feature.discretization.EqualFreq(n=3), clean=True):
         self.features = features
         self.discretize_class = discretize_class
         self.method = method

Orange/fixes/fix_changed_names.py

 
            "orange.EntropyDiscretization": "Orange.feature.discretization.Entropy",
            "orange.EquiDistDiscretization": "Orange.feature.discretization.EqualWidth",
-           "orange.EquiNDiscretization": "Orange.data.discretization.EqualFreq",
-           "orange.BiModalDiscretization": "Orange.data.discretization.BiModal",
+           "orange.EquiNDiscretization": "Orange.feature.discretization.EqualFreq",
+           "orange.BiModalDiscretization": "Orange.feature.discretization.BiModal",
 
            "orngFSS.attMeasure": "Orange.feature.scoring.score_all",
            "orngFSS.bestNAtts": "Orange.feature.selection.top_rated",

Orange/orng/orngPCA.py

 from numpy import sqrt, abs, dot, transpose
 from numpy.linalg import eig, inv
 
-mathlib_import = True
-try:
-    import matplotlib.pyplot as plt
-except:
-    import warnings
-    warnings.warn("Importing of matplotlib has failed.\nPlotting functions will be unavailable.")
-    mathlib_import = False
-
 #color table for biplot
 Colors = ['bo', 'go', 'yo', 'co', 'mo']
 
         filename : File name under which plot will be saved (default: scree_plot.png)
             If None, plot will be shown
         """
-
-        if not mathlib_import:
-            raise orange.KernelException, "Matplotlib was not imported!"
-
-        #plt.clf() -> opens two windows
+        import pylab as plt
         fig = plt.figure()
         ax = fig.add_subplot(111)
 
         filename : File name under which plot will be saved (default: biplot.png)
             If None, plot will be shown
         """
-
-        if not mathlib_import:
-            raise orange.KernelException, "Matplotlib was not imported!"
+        import pylab as plt
 
         if self._dataMatrix == None:
             raise orange.KernelException, "No data available for biplot!"

Orange/testing/regression/tests_20/exclude-from-regression.txt

 modules_server_files1.py
 modules_server_files2.py
 reference_matrix.py
-__init__.py
+__init__.py
+reference_c45.py

Orange/testing/testing.py

     __IPYTHON__  #We are running tests from ipython
     if getattr(__IPYTHON__.shell, "call_pdb", None): # Is pdb enabled
         enable_pdb()
-except NameError:
+except:
     pass
 
 

Orange/testing/unit/tests/__init__.py

+import os
+import unittest
+if not hasattr(unittest.TestLoader, 'discover'):
+    import unittest2 as unittest
+
+
+def suite():
+    test_dir = os.path.dirname(__file__)
+    return unittest.TestLoader().discover(test_dir, )
+
+test_suite = suite()
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')

Orange/testing/unit/tests/test_regression.py

     import unittest
 import subprocess
 
+import Orange
 from Orange.utils import environ
 from Orange.testing import testing
 
 
 class TestRegression(unittest.TestCase):
-
     PLATFORM = sys.platform
     PYVERSION = sys.version[:3]
     STATES = ["OK", "timedout", "changed", "random", "error", "crash"]
+    maxDiff = None
+
+    def __init__(self, methodName='runTest'):
+        super(TestRegression, self).__init__(methodName)
+        self.orange_dir = os.path.dirname(Orange.__file__)
+        self.orange_dir = os.path.join(self.orange_dir, '..')
+        self.orange_dir = os.path.realpath(self.orange_dir)
 
     def setUp(self):
-        pass
+        sys.path.append(self.orange_dir)
+
+    def tearDown(self):
+        del sys.path[-1]
 
     def test_regression_on(self, roottest, indir, outdir, name):
         for state in TestRegression.STATES:
 
         stdout, stderr = p.communicate()
         rv = stdout.strip().lower()
+        if rv == 'error':
+            self.assertEqual(stderr.split('\n'), [])
+        elif rv == 'changed':
+            expected_results = self.get_expected_results(outdir, name)
+            actual_results = self.get_actual_results(outdir, name)
+            self.assertEqual(actual_results, expected_results)
+
+
         self.assertEqual(rv, "ok", "Regression test %s: %s" % (rv, name) \
                         if stderr == "" else \
                         "Regression test %s: %s\n\n%s" % (rv, name, stderr))
         os.chdir(tmpdir)
 
+    def get_expected_results(self, outputdir, name):
+        expected_results = "%s/%s.%s.%s.txt" % (outputdir, name, sys.platform, sys.version[:3])
+        if not os.path.exists(expected_results):
+            expected_results = "%s/%s.%s.txt" % (outputdir, name, sys.platform)
+            if not os.path.exists(expected_results):
+                expected_results = "%s/%s.txt" % (outputdir, name)
+
+        with open(expected_results, 'r') as results:
+            return results.read().split('\n')
+
+    def get_actual_results(self, outputdir, name):
+        for state in TestRegression.STATES:
+            actual_results = "%s/%s.%s.%s.%s.txt" % (
+                outputdir, name, TestRegression.PLATFORM,
+                TestRegression.PYVERSION, state)
+
+            if os.path.exists(actual_results):
+                with open(actual_results, 'r') as results:
+                    return results.read().split('\n')
+
+
 root = os.path.normpath(os.path.join(environ.install_dir, ".."))
 roottest = os.path.join(root, "Orange/testing/regression")
 

Orange/utils/addons.py

 with closing(open_addons()) as addons:
     addons_corrupted = len(addons)==0
 
+del addons
+
 addon_refresh_callback = []
 
 global index
 editing the setup-site.cfg file in this directory (see the comments
 in that file for instructions on how to do that).
 
+Running tests
+-------------
+After Orange is installed, you can check if everything is working OK by running the included tests::
+
+    python setup.py test
+
+This command runs all the unit tests and documentation examples. Some of the latter have additional dependencies you can satisfy by installing matplotlib, PIL and scipy.
+
 Starting Orange Canvas
 ----------------------
 

docs/development/rst/c.rst

 Writing Orange Extensions in C++
 ################################
 
-This page is a draft of documentation for writing Orange extensions in C++. It has been written quite a while ago and never really polished, but we publish it due to requests and questions about the topic.
+This page gives an introduction to extending Orange in C++ with emphasis on
+how to define interfaces to Python. Besides reading this page, we recommend
+studying some of existing extension modules like orangeom, and the Orange's
+interface itself.
 
-This page starts with a simple example of a C function that gets the data from Orange's example table and computes Delaunay triangulation for a chosen pair of (continuous) attributes. The result is returned as ``orange.Graph``. Then follows a more complex example that shows how to derive a new class from one of Orange's classes and make it accessible from Python. Finally, there's a more concise description of Orange's interface to Python and the tools we developed for making our lives easier.
+We shall first present a general picture and then focus on specific parts of the
+interface.
 
-***************************************
-A simple example: Exporting function(s)
-***************************************
+Instead of general tools for creating interfaces between C++ and Python
+(Swig, Sip, PyBoost...), Orange uses its own specific set of tools.
 
-If you plan to develop your own extensions for Orange, you'll need the Orange sources. Besides headers, you will certainly need the C files for stealing parts of the code from them. So download them if you haven't already done so. The example shown in this section is from directory orange/orangeom, files triangulate.cpp and orangeom.cpp.
+To expose a C++ object to Python, we need to mark them as exportable, select a
+general constructor template to use or program a specific one, we have to mark
+the attributes to be exported, and provide the interfaces for C++ member
+functions. When we give the access to mostly C++ code as it is, the interface
+functions have only a few lines. When we want to make the exported function more
+friendly, eg. allow various types of arguments or fitting the default arguments
+according to the given ones, these functions are longer.
 
-We also assume that you have at least a vague idea about the Python API. If you don't, read the Python documentation first. Don't be afraid, API is fairly simple and very nicely organized.
+To define a non-member function, we write the function itself as described in
+the Python's manual (see the first chapter of "Extending and Embedding the
+Python Interpreter") and then mark it with a specific keyword.
+Pyxtract will recognize the keyword and add it to the list of exported functions.
 
-We shall write a function that gets examples, indices/names/descriptors of two attributes and the number edge types. The two attributes need to be discrete; the function treats the values of these two attributes for each example as a point in a plane and computes the Delaunay triangulation, which is returned as ``orange.Graph``.
+To define a special method, one needs to provide a function with the appropriate
+name constructed from the class name and the special method's name, which is the
+same as in Python's PyTypeObjects.
 
-The function should be declared like this::
-
-    PyObject *triangulate(PyObject *, PyObject *args, PyObject *)
-        PYARGS(METH_VARARGS, "(examples[, attr1, attr2, nEdgeTypes]) -> Graph")
-
-This all should be written in a single line. Function arguments and result are like for any Python function (as you have learned while reading Python's documentation), while the macro PYARGS marks the function for export to Python. The macro is dummy and serves only as a marker. The first argument tells Python about the types of arguments (again, you've seen the constant METH_VARARGS in Python's docs), and the second string describes the functions arguments and/or what the function does.
-
-We shall close the function in ``PyTRY`` - ``PyCATCH`` block. This catches any C++ exceptions that Orange might throw and turns them into Python error messages. You should do this with any your function that calls orange's functions to be sure that you catch anything that's thrown from in there. ::
-
-    {
-        PyTRY
-        ...
-        PyCATCH
-    }
-
-Now for the real code. First we need to get the arguments and check their types. ::
-
-    PExampleGenerator egen;
-    int nEdgeTypes = 1;
-    PyObject *pyvar1 = NULL, *pyvar2 = NULL;
-    int attr1 = 0, attr2 = 1;
-    if (!PyArg_ParseTuple(args, "O&|OOi:triangulate", pt_ExampleGenerator, &egen, &pyvar1, &pyvar2, &nEdgeTypes)
-        || pyvar1 && !varNumFromVarDom(pyvar1, egen->domain, attr1)
-        || pyvar2 && !varNumFromVarDom(pyvar2, egen->domain, attr2))
-      return NULL;
-
-    if ((egen->domain->attributes->at(attr1)->varType != TValue::FLOATVAR)
-            || (egen->domain->attributes->at(attr2)->varType != TValue::FLOATVAR))
-        PYERROR(PyExc_TypeError, "triangulate expects continuous attributes", NULL);
-
-For the arguments of ``PyArg_ParseTuple`` see the corresponding Python documentation. Here we accept from one to four arguments. The first is a table of examples, which gets converted to ``PExampleGenerator`` by a converter function ``pt_ExampleGenerator``. The next two are read as Python objects and can be, as far as ``PyArg_ParseTuple`` is concerned, of any type. The last argument is an integer.
-
-We use Orange's function ``varNumFromVarDom`` to convert what the user passed as an attribute to an attribute index. (This function is not documented anywhere, but you can discover such functions by looking at the orange's functions that do similar things as the function you plan to write.) If the argument is already an integer, it is returned as such; otherwise the example table's domain (``egen->domain``) is used to convert a name or an attribute descriptor to an integer index.
-
-We then check the attribute's type and complain if they are not continuous. Macro ``PYERROR``, defined in Orange, is used to set the error type (``PyExc_TypeError``) and message, and to send the corresponding result (in Python ``NULL`` always signifies an error).
-
-For the actual triangulation we shall use Wml, which expects the arguments in a structure ``Vector2<float>``. ::
-
-    const int nofex = egen->numberOfExamples();
-
-    Vector2<float> *points = new Vector2<float>[nofex];
-    Vector2<float> *pi = points;
-
-    PEITERATE(ei, egen) {
-        if ((*ei)[attr1].isSpecial() || (*ei)[attr2].isSpecial())
-            PYERROR(PyExc_AttributeError, "triangulate cannod handle unknown values", NULL);
-
-        *(pi++) = Vector2<float>((*ei)[attr1].floatV, (*ei)[attr2].floatV);
-    }
-
-    int nTriangles;
-    int *triangles, *adjacent;
-    Delaunay2a<float> delaunay(nofex, points, nTriangles, triangles, adjacent);
-    delete adjacent;
-
-We have used a macro ``PEITERATE(ei, egen)`` for iteration across the example table, where ``egen`` is an example generator and ``ei`` is an iterator (declared by the macro). If we wanted, we could use an equivalent ``for`` loop: ``for(TExampleIterator ei(egen->begin()); ei; ++ei)``. Of the two results computed by ``Delaunay2a&lt;float&gt;``, we immediately discard ``adjacent``, while from ``triangles`` we shall construct the graph. ::
-
-    TGraph *graph = new TGraphAsList(nofex, nEdgeTypes, 0);
-    PGraph wgraph = graph;
-    try {
-        for(int *ti = triangles, *te = ti+nTriangles*3; ti!=te; ti+=3) {
-            for(int se = 3; se--; ) {
-                float *gedge = graph->getOrCreateEdge(ti[se], ti[(se+1) % 3]);
-                for(int et = nEdgeTypes; et--; *gedge++ = 1.0);
-            }
-        }
-    }
-    catch (...) {
-        delete triangles;
-        throw;
-    }
-    delete triangles;
-
-The ``graph`` is immediately wrapped into an instance of ``PGraph``. If anything fails, for instance, if an exception occurs in the code that follows, ``graph`` will be deallocated automatically so we don't need to (and even mustn't!) care about it. However, we have to be careful about the ``triangles``, we need another ``try``-``catch`` to deallocate it in case of errors. Then follows copying the data from ``triangles`` into ``graph`` (we won't explain it here, look at Wml's documentation if you are that curious).
-
-``TGraph`` is Orange's class and ``PGraph`` is a wrapper around it. Python can use neither of them, the only type of result that the function can return is a Python object, so we conclude by::
-
-    PyObject *res = WrapOrange(wgraph);
-    return res;
-
-(Don't worry about double wrappers. ``WrapOrange``, which wraps Orange objects into ``PyObject *`` technically does the opposite - it partially unwraps ``PGraph`` which already includes a ``PyObject *``. See the Orange's garbage collector, garbage.hpp, if you need to know.)
-
-There's another detail in the actual function ``triangulate`` which is rather dirty and quite specific and rare, so we won't explain it here. If you're looking at triangulate.cpp and wonder what it means, just ignore it. It's not important.
-
-We have omitted a few #includes above the function. We need a few wml headers. Besides that, all extensions should include orange_api.hpp that defines several macros and similar. In our case, we also needed to include graph.hpp and examplegen.hpp which define the classes used in our function.
-
-What remains is to export this function to Python. We need to construct a new module, it's name will be ``orangeom`` and it will export the function triangulate. We've already mentioned that this has something to do with ``PYARGS`` macro. It has two arguments, the first, ``METH_VARARGS`` giving the number and type of arguments, while the second is the documentation string. Assuming that ``triangulate.cpp`` is in directory source/orangeom, so source/orange is its sibling directory, we need to run ../pyxtract/pyxtract.py like this::
-
-    python ../pyxtract/pyxtract.py -m -n orangeom -l ../orange/px/stamp triangulate.cpp
-
-Do yourself a favour and put this line into a batch file. See the ``_pyxtract.bat`` files in various Orange's directories.
-
-Option ``-m`` tells pyxtract to ``m``ake the file, ``-n orangeom`` gives the name of the module to be produced and ``-l ../orange/px/stamp`` is similar to gcc's ``-l`` - it tells pyxtract to include a "library" with all Orange's objects (don't worry, it's not code, there are just things that pyxtract has written down for himself). Then follow the names of the files with any exported functions and classes. In our case, this is a single file, triangulate.cpp.
-
-What do we get from pyxtract? A few files we don't need and one more we don't care about. The only file of real interest for us is initialization.px. You can see the file for yourself, but omitting a few unimportant points, it looks like this. ::
-
-    PyMethodDef orangeomFunctions[] = {
-        {"triangulate", (binaryfunc)triangulate, METH_VARARGS, "(examples[, attr1, attr2, nEdgeTypes]) -> Graph"},
-        {NULL, NULL}
-    };
-
-    PyObject *orangeomModule;
-
-    extern "C" ORANGEOM_API void initorangeom()
-    {
-        if (!initorangeomExceptions())
-            return;
-
-        gcorangeomUnsafeStaticInitialization();
-        orangeomModule = Py_InitModule("orangeom", orangeomFunctions);
-    }
-
-``initorangeom`` is a function that will be called by Python when the module is initialized. Basically, it calls ``initorangeomExceptions``, ``gcorangeomUnsafeInitialization`` and then ``Py_InitModule`` whom it tells the module name and gives it the list of function that the module exports - in our case, ``orangeomFunctions`` has only a pointer to ``triangulate`` we wrote above.
-
-Functions ``initorangeomExceptions``, ``gcorangeomUnsafeInitialization`` initialize the exceptions your module will throw to Python and initializes the stuff that cannot be initialized before the class types are ready. Both functions need to be provided by our module, but since we don't have any work for them, we'll just define them empty.
-
-So, we need to write a file that will include initialization.px. It should be like this. ::
-
-    #include "orange_api.hpp"
-
-    #ifdef _MSC_VER
-        #define ORANGEOM_API __declspec(dllexport)
-    #else
-        #define ORANGEOM_API
-    #endif
-
-
-    bool initExceptions()
-    { return true; }
-
-    void gcUnsafeStaticInitialization()
-    {}
-
-    #include "px/initialization.px"
-
-We simplified the definition of ``ORANGEOM_API`` for this guide. If you ever wrote a DLL yourself, you probably know what the complete definition would look like, but for our module this will suffice. You can see the complete definition in ``orangeom.cpp`` if you want to. Then follow the two functions that we need to provide only because they are called by ``initorangeom``. Finally, we include initialization.px which takes care of the rest.
-
-Setting the compiler options? Eh, just copy them from some project that is delivered together with Orange. If you want to do it yourself, this is the complete recipe (unless we've forgotten about something :)
-
-* Add an environment variable ``PYTHON=c:\python23``, or wherever your
-Python is installed. This will simplify the options and also help
-you upgrade to a newer version. (If you don't want to do this,
-just replace the below reference ``$(PYTHON)`` with ``c:\python23``.)
-
-* Open the Orange workspace (sources/orange.dsw) and add your stuff as new projects.
-Add new project into workspace". You need a "Win32 Dynamic-link
-Library"; create it as an empty or simple project.
-This document will suppose you've put it into a subdirectory
-of ``orange/source`` (eg ``orange/source/myproject``)
-
-* Edit the project settings. Make sure to edit the settings for
-both Release and Debug version - or for Release, in the unlikely case that you won't
-need to debug.
-  * In C/C++, Preprocessor add include directories ``../include,../orange,px,ppp,$(PYTHON)/include``.
-      If VC later complains that it cannot find Python.h, locate the
-      file yourself and fix the last include directory accordingly.
-  
-
-  * In C/C++, C++ Language, check Enable Run-Time Type Information.
-
-  * In C/C++, Code generation, under Use run-time library choose
-      Multithread DLL for Release and Debug Multithread DLL for Debug
-      version.
-
-  * In Link, Input, add ``$(PYTHON)\libs`` and ``../../lib`` to
-      Additional Library Path. (The first is the path to Python.lib,
-      and the second to orange.lib; locate them manually if you need to.)
-
-  * In Link, General, change the Output file name to ../../mymodule.pyd for the Release Build and to ../../mymodule_d.pyd for debug. You can use .dll instead of .pyd.
-
-  * In Post-build step, add "copy Release\orangeom.lib ..\..\lib\orangeom.lib" for the Release version, and "copy Debug\orangeom_d.lib ..\..\lib\orangeom_d.lib" for the Debug.
-
-  * In Debug Build, go to tab Debug, General, set the Executable for debug session to "c:\python23\python_d.exe".
-
-##################################################################
-General mechanism and tools used in Orange's C to Python interface
-##################################################################
-
-This page is not meant to be a comprehensive and self-sufficient guide to exporting C++ classes into Python using the Orange's machinery. To learn how to export your functions and classes to Python, you should open some Orange's files (lib_*.cpp and cls_*.cpp) and search for examples there, while this page will hopefully help you to understand them. The easiest way to write your interfaces will be to copy and modify the existing Orange's code. (This is what we do all the time. :)
-
-If you are writing extension modules for Python, you by no means *have to* use Orange's scripts (pyxtract, pyprops) compiling the interface. Compile your interface with any tool you want, e.g. Swig. The only possible complications would arise if you are deriving and exporting new C++ classes from Orange's classes (to those that know something on the topic: Orange uses a slightly extended version of ``PyTypeObject``, and the derived classes can't return to the original). If need be, ask and we may try to provide some more insight and help to overcome them.
-
-################################
-Orange's C++ to Python interface
-################################
-
-Instead of general 3rd party tools (Swig, Sip, PyBoost...) for interfacing between C++ and Python, Orange uses it's own set of tools. (We are working towards making them general, ie also useful for other applications.) These tools (two Python scripts, actually, pyprops and pyxtract) require more manual programming than other tools, but on the other hand, the result is a tighter and nicer coupling of Orange with Python.
-
-In short, to expose a C++ object to Python, we mark the attributes to be exported by a comment line starting with ``//P``. Besides, we need to either declare which general constructor to use or program a special one (this constructor will be in place of what would in Python be defined as the function __new__), and program the interfaces to those C++ member functions that we want exported. In order for pyxtract to recognize them, the function name should be composed of the class name and method name, separated by an underscore, and followed by a certain keyword. When we simply give the access to unaltered C++ functionality, the interface functions will only have a few-lines. When we want to make the "Python" version of the function more friendly, eg. allow various types of arguments or fitting the default arguments according to the given, these functions will be longer, but the pay-off is evident. We argue that a few-line function is not more of inconvenience than having to write export declarations (as is the case with Sip at least, I guess).
-
-To define a non-member function, we write the function itself according to the instructions in Python's manual (see the first chapter of "Extending and Embedding the Python Interpreter") and then mark it with a specific keyword. Pyxtract will recognize the keyword and add it to the list of exported functions.
-
-Orange's core C++ objects are essentially unaware of Python above them. However, to facilitate easier interface with Python, each Orange class contains a static pointer to a list of its ``properties'' (attributes, in Python terminology). Accessing the object's attributes from Python goes through that list. These lists, however, are general and would be equally useful if we were to interface Orange to some other language (eg Perl) or technology (ActiveX, Corba).
-
-The only exception to the Orange's independency of Python is garbage collection: Orange uses Python's garbage collection for the sake of efficiency and simplicity. Each Orange's pointer (except for the short-term ones) is wrapped into a wrapper of type ``PyObject *``. Dependency of Orange on Python is not strong - if we wanted to get rid of it, we'd only need to write our own garbage collection (or steal the Python's). ``PyObject *`` is the basic Python's type which stores some garbage collection related stuff, a pointer to the class type (``PyTypeObject *``) and the class specific data. The specific data is, in Orange's case, a pointer to the Orange object. Class type is a structure that contains the class name, pointers to function that implement the class special methods (such as indexing, printing, memory allocation, mathematical operations) and class members.
-
-We won't go deeper into explaining ``PyTypeObject`` since this is done in Python documentation. What you need to know is that for each Orange class that is accessible from Python, there is a corresponding ``PyTypeObject`` that defines its methods. For instance, the elements of ``ExampleTable`` (examples) can be accessed through indexing because we defined a C function that gets an index (and the table, of course) and returns the corresponding example, and we've put a pointer to this method into the ``ExampleTable``'s ``PyTypeObject`` (actually, we didn't do it manually, this is what pyxtract is responsible for). This is equivalent to overloading the operator [] in C++. Here's the function (with error detection removed for the sake of clarity). ::
+For instance, the elements of ``ExampleTable`` (examples) can be accessed
+through indexing because we defined a C function that gets an index (and the
+table, of course) and returns the corresponding example. Here is the function
+(with error detection removed for the sake of clarity). ::
 
     PyObject *ExampleTable_getitem_sq(PyObject *self, int idx)
     {
         return Example_FromExampleRef((*table)[idx], EXAMPLE_LOCK(PyOrange_AsExampleTable(self)));
     }
 
-Also, ``ExampleTable`` has a method ``sort([list-of-attributes])``. This is implemented through a C function that gets a list of attributes and calls the C++ class' method ``TExampleTable::sort(const vector&lt;int&gt; order)``. To illustrate, this is a slightly simplified function (we've removed some flexibility regarding the parameters and the exception handling). ::
+Also, ``ExampleTable`` has a non-special method ``sort([list-of-attributes])``.
+This is implemented through a C function that gets a list of attributes and
+calls the C++ class' method
+``TExampleTable::sort(const vector<int> order)``. To illustrate, this is a
+slightly simplified function (we've removed some flexibility regarding the
+parameters and the exception handling). ::
 
     PyObject *ExampleTable_sort(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "() -> None")
     {
         TVarList attributes;
         varListFromDomain(PyTuple_GET_ITEM(args, 0), table->domain, attributes, true, true);
         vector<int> order;
-        for(TVarList::reverse_iterator vi(attributes.rbegin()), ve(attributes.rend()); vi!=ve; vi++)
+        for(TVarList::reverse_iterator vi(attributes.rbegin()), ve(attributes.rend()); vi!=ve; vi++) {
             order.push_back(table->domain->getVarNum(*vi));
-
+        }
         table->sort(order);
         RETURN_NONE;
     }
 
-Basically, what the function does is it casts the ``PyObject *`` into the corresponding C++ object ("unwrapping"), reads the arguments, calls the C++ functions and returns the result (``None``, in this case).
+The function casts the ``PyObject *`` into the
+corresponding C++ object, reads the arguments, calls the C++
+functions and returns the result (``None``, in this case).
 
-There seem to be a lot of manual work involved in interfacing. Indeed there is, but this is exactly why Orange is so user friendly. The manual control of argument conversion gives a programmer the opportunity to program a function which accepts many different forms of arguments. The above function, for instances, can accept the list where the attributes can be specified by indices, names or descriptors, all corresponding to the ``ExampleTable`` which is being sorted. Inheritance of methods, on the other hand, ensures that only the methods that are truly specific for a class need to be coded.
+Interfacing with Python requires a lot of manual work, but this gives a
+programmer the opportunity to provide a function which accepts many different
+forms of arguments. The above function, for instance, accepts a list in
+which attributes are specified by indices, names or descriptors, all
+corresponding to the ``ExampleTable`` which is being sorted. Inheritance of
+methods, on the other hand, ensures that only the methods that are truly
+specific for a class need to be coded.
 
-
-The part of the interface that is programmed automatically is taken care of by two scripts. ``pyprops.py`` parses all Orange's header files and extracts all the class built-in properties. The result are lists of properties (attributes); nothing else needs to be done for the ``ExampleTable``'s attribute ``domain`` to be visible in Python, except for putting a ``// P`` after its declaration.
-
-The second script is ``pyxtract.py``. It goes through the C++ files that contain the interface functions, such as those above. It recognizes the functions that implement special or member methods and constructs the corresponding ``PyTypeObject``s. It therefore relieves us from the most boring part of work, but permits us to program things like more intelligent arguments or error handling.
+The part of the interface that is built automatically is taken care of by
+two scripts. ``pyprops`` parses all Orange's header files and extracts all
+the class built-in properties. The second is ``pyxtract``, which goes
+through the C++ files that contain the interface functions such as those above.
+It recognizes the functions that implement special or member methods and
+constructs the corresponding ``PyTypeObject``s.
 
 *******
 pyprops
 *******
 
-Pyprops scans each hpp file for classes we want to export to Python (or, in general, some other scripting language). Properties can be ``bool``, ``int``, ``float``, ``string``, ``TValue`` or a wrapped Orange type.
+Pyprops scans each hpp file for classes we want to export to Python). Properties
+can be ``bool``, ``int``, ``float``, ``string``, ``TValue`` or a wrapped Orange
+type.
 
-Pyprops' parser is essentially a trivial finite automaton. Class definition needs to look as follows. ::
+Class definition needs to look as follows. ::
 
     class [ORANGE_API] <classname>; [: public <parentclass> ]
 
-This should be in a single line. To mark the class for export, this should be followed by ``__REGISTER_CLASS`` or ``__REGISTER_ABSTRACT_CLASS`` before any properties or components are defined. The difference between the two, as far as pyprops is concerned, is that abstract classes don't define the ``clone`` method.
+This should be in a single line. To mark the class for export, this should be
+followed by ``__REGISTER_CLASS`` or ``__REGISTER_ABSTRACT_CLASS`` before any
+properties or components are defined. The difference between the two, as far as
+pyprops is concerned, is that abstract classes do not define the ``clone``
+method.
 
 To export a property, it should be defined like this. ::
 
     <type> <name> //P[R|O] [>|+<alias>] <description>
 
-Pyprops doesn't check the type and won't object if you use other types than those listed above. Linker will complain about missing symbols, though. ``//P`` signals that we want to export the property. If followed by R or O, the property is read-only or obsolete. The property can also have an alias name; > renames it and + adds an alias. Description is not used at the time, but it is nevertheless a good practice to provide it.
+Pyprops doesn't check the type and won't object if you use other types than
+those listed above. The error will be discovered later, during linking. ``//P``
+signals that we want to export the property. If followed by ``R`` or ``O``, the
+property is read-only or obsolete. The property can also have an alias name;
+``>`` renames it and ``+`` adds an alias.
 
 Each property needs to be declared in a separate line, e.g. ::
 
     int x; //P;
     int y; //P;
 
-If we don't want to export a certain property, we don't need to. Just omit the ``//P``. An exception to this are wrapped Orange objects: for instance, if a class has a (wrapped) pointer to the domain, ``PDomain`` and it doesn't export it, pyxtract should still now about them because of the cyclic garbage collection. You should mark them by ``//C`` so that they are put into the list of objects that need to be counted. If you fail to do so, you'll have a memory leak. Luckily, this is a very rare situation; there are only two such components in relief.hpp.
+If we don't want to export a certain property, we omit the ``//P`` mark. An
+exception to this are wrapped Orange objects: for instance, if a class has a
+(wrapped) pointer to the domain, ``PDomain`` and it doesn't export it, pyxtract
+should still know about them because for the purpose of garbage collection. You
+should mark them by ``//C`` so that they are put into the list of objects that
+need to be counted. Failing to do so would cause a memory leak.
 
-If a class directly or indirectly holds references to any wrapped objects that are neither properties nor components, it will need to declare ``traverse`` and ``clear`` to include them in the garbage collection. Python documentation will tell you what these functions need to do, and you can look at several instances where we needed them in Orange.
+If a class directly or indirectly holds references to any wrapped objects that
+are neither properties nor components, it needs to declare ``traverse`` and
+``clear`` as described in Python documentation.
 
-Pyprops creates a ppp file for each hpp. The ppp file first ``#include``s the corresponding hpp file and then declares the necessary definition for each exported file. A list of properties store their names, descriptions, typeid's (RTTI), a class description for the properties' type, the properties' offset and the flags denoting read-only and obsolete properties.
-
-Then comes a list of components' offsets, followed by a definition of classes static field ``st_classDescription`` and a virtual function ``classDescription`` that returns a pointer to it. Finally, if the class is not abstract, a virtual function ``clone`` is defined that returns a ``new`` instance of this class initialized, through a copy constructor, with an existing one.
-
-ppp file contains definitions, so it has to be compiled only once. The most convenient way to do it is to include it in the corresponding cpp file. For instance, while many Orange's cpp files include domain.hpp, only domain.cpp includes domain.ppp instead.
+Pyprops creates a ppp file for each hpp, which includes the extracted
+information in form of C++ structures that compile into the interface.
+The ppp file needs to be included in the corresponding cpp file. For
+instance, domain.ppp is included in domain.cpp.
 
 ********
 pyxtract
 ********
 
-Pyxtract's job is to detect the functions that define special methods (such as printing, conversion, sequence and arithmetic related operations...) and member functions. Based on what it finds for each specific class, it constructs the corresponding ``PyTypeObject``s. For the functions to be recognized, they must follow a specific syntax.
+Pyxtract's job is to detect the functions that define special methods (such as
+printing, conversion, sequence and arithmetic related operations...) and member
+functions. Based on what it finds for each specific class, it constructs the
+corresponding ``PyTypeObject``s. For the functions to be recognized, they must
+follow a specific syntax.
 
-There are two basic mechanisms used. Special functions are recognized by their definition (they need to return ``PyObject *``, ``void`` or ``int`` and their name must be of form &lt;classname&gt;_&lt;functionname&gt;). Member functions, inheritance relations, constants etc. are marked by macros such as ``PYARGS`` in the above definition of ``ExampleTable_sort``. These macros usually don't do anything, so C++ compiler ignores them - they are just markups for pyxtract.
+There are two basic mechanisms for marking the functions to export. Special
+functions are recognized by their definition (they need to return
+``PyObject *``, ``void`` or ``int`` and their name must be of form
+<classname>_<functionname>). Member functions,
+inheritance relations, constants etc. are marked by macros such as ``PYARGS``
+in the above definition of ``ExampleTable_sort``. Most of these macros don't do
+anything except for marking stuff for pyxtract.
 
 Class declaration
 =================
 
-Each class needs to be declared: pyxtract must know from which parent class the class it's derived. If it's a base class, pyxtract need to know the data structure for the instances of this class. As for all Python objects the structure must be "derived" from ``PyObject`` (the quotation mark are here because Python is written in C, so the subclasses are not derived in the C++ sense). Most objects are derived from Orange; the only classes that are not are ``orange.Example``, ``orange.Value`` and ``orange.DomainDepot`` (I forgot why the depot, but there had to be a strong reason).
+Each class needs to be declared as exportable. If it's a base class, pyxtract
+needs to know the data structure for the instances of this class. As for all
+Python objects the structure must be "derived" from ``PyObject`` (Python is
+written in C, so the subclasses are not derived in the C++ sense but extend the
+C structure instead). Most objects are derived from Orange; the only exceptions
+are ``orange.Example``, ``orange.Value`` and ``orange.DomainDepot``.
 
-Pyxtract should also know how the class is constructed - it can have a specific constructor, one of the general constructors or no constructor at all.
+Pyxtract should also know how the class is constructed - it can have a specific
+constructor, one of the general constructors or no constructor at all.
 
-
-The class is declared in one of the following ways.
+The class is declared in one of the following ways (here are some examples from
+actual Orange code).
 
 ``BASED_ON(EFMDataDescription, Orange)``
     This tells pyxtract that ``EFMDataDescription`` is an abstract class derived from ``Orange``: there is no constructor for this class in Python, but the C++ class itself is not abstract and can appear and be used in Python. For example, when we construct an instance of ``ClassifierByLookupTable`` with more than three attributes, an instance of ``EFMDataDescription`` will appear in one of its fields.
 
 ``ABSTRACT(ClassifierFD, Classifier)``
-    This defines an abstract class, which will never be constructed in the C++ code and not even pretend to be seen in Python. At the moment, the only difference between this ``BASED_ON`` and ``ABSTRACT`` is that the former can have pickle interface, while the latter don't need one. 
+    This defines an abstract class, which will never be constructed in the C++ code. The only difference between this ``BASED_ON`` and ``ABSTRACT`` is that the former can have pickle interface, while the latter don't need one.
 
-Abstract C++ classes are not necessarily defined as ``ABSTRACT`` in the Python interface. For example, ``TClassifier`` is an abstract C++ class, but you can seemingly construct an instance of ``Classifier`` in Python. What happens is that there is an additional C++ class ``TClassifierPython``, which poses as Python's class ``Classifier``. So the Python class ``Classifier`` is not defined as ``ABSTRACT`` or ``BASED_ON`` but using the ``Classifier_new`` function, as described below.
+Abstract C++ classes are not necessarily defined as ``ABSTRACT`` in the Python
+interface. For example, ``TClassifier`` is an abstract C++ class, but you can
+seemingly construct an instance of ``Classifier`` in Python. What happens is
+that there is an additional C++ class ``TClassifierPython``, which poses as
+Python's class ``Classifier``. So the Python class ``Classifier`` is not defined
+as ``ABSTRACT`` or ``BASED_ON`` but using the ``Classifier_new`` function, as
+described below.
 
 
 ``C_NAMED(EnumVariable, Variable, "([name=, values=, autoValues=, distributed=, getValueFrom=])")``
-    ``EnumVariable`` is derived from ``Variable``. Pyxtract will also create a constructor which will as an optional argument accept the object's name. The third argument is a string that describes the constructor, eg. gives a list of arguments. IDEs for Python, such as PythonWin, will show this string in a balloon help while the programmer is typing.
+    ``EnumVariable`` is derived from ``Variable``. Pyxtract will also create a constructor which will accept the object's name as an optional argument. The third argument is a string that describes the constructor, eg. gives a list of arguments. IDEs for Python, such as PythonWin, will show this string in a balloon help while the programmer is typing.
 
 ``C_UNNAMED(RandomGenerator, Orange, "() -> RandomGenerator")``
     This is similar as ``C_NAMED``, except that the constructor accepts no name. This form is rather rare since all Orange objects can be named.
 
 ``C_CALL(BayesLearner, Learner, "([examples], [weight=, estimate=] -/-> Classifier")``
-    ``BayesLearner`` is derived from ``Learner``. It will have a peculiar constructor. It will, as usual, first construct an instance of ``BayesLearner``. If no arguments are given (except for, possibly, keyword arguments), it will return the constructed instance. Otherwise, it will call the ``Learner``'s call operator and return its result instead of ``BayesLearner``.``
+    ``BayesLearner`` is derived from ``Learner``. It will have a peculiar constructor. It will, as usual, first construct an instance of ``BayesLearner``. If no arguments are given (except for, possibly, keyword arguments), it will return the constructed instance. Otherwise, it will call the ``Learner``'s call operator and return its result instead of ``BayesLearner``.
 
 ``C_CALL3(MakeRandomIndices2, MakeRandomIndices2, MakeRandomIndices, "[n | gen [, p0]], [p0=, stratified=, randseed=] -/-> [int]")``
     ``MakeRandomIndices2`` is derived from ``MakeRandomIndices`` (the third argument). For a contrast from the ``C_CALL`` above, the corresponding constructor won't call ``MakeRandomIndices`` call operator, but the call operator of ``MakeRandomIndices2`` (the second argument). This constructor is often used when the parent class doesn't provide a suitable call operator.
 ``DATASTRUCTURE(Orange, TPyOrange, orange_dict)``
     This is for the base classes. ``Orange`` has no parent class. The C++ structure that stores it is ``TPyOrange``; ``TPyOrange`` is essentially ``PyObject`` (again, the structure always has to be based on ``PyObject``) but with several additional fields, among them a pointer to an instance of ``TOrange`` (the C++ base class for all Orange's classes). ``orange_dict`` is a name of ``TPyOrange``'s field that points to a Python dictionary; when you have an instance ``bayesClassifier`` and you type, in Python, ``bayesClassifier.someMyData=15``, this gets stored in ``orange_dict``. The actual mechanism behind this is rather complicated and you most probably won't need to use it. If you happen to need to define a class with ``DATASTRUCTURE``, you can simply omit the last argument and give a 0 instead.
 
-``PyObject *ClassifierByLookupTable1_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(ClassifierByLookupTable, "(class-descriptor, descriptor)")``
-    ``ClassifierByLookupTable1_new`` has a specific constructor. The general ones above couldn't be used since this constructor needs to have some arguments or for some other reason (eg. the user doesn't need to specify the arguments, but the C++ constructor for the corresponding C++ class requires them, so this interface function will provide the defaults). The constructor function needs to be defined like above (ie. &lt;classname&gt;_new), followed by a ``BASED_ON`` macro giving the parent class and the comment. The declaration must be written in a single line. Just for the illustration, the (simplified, no error handling) constructor looks like this ::
+Even if the class is defined by ``DATASTRUCTURE``, you can still specify a
+different constructor, most probably the last form of it (the ``_new``
+function). In this case, specify a keyword ``ROOT`` as a parent and pyxtract
+will understand that this is the base class.
 
-    PyObject *ClassifierByLookupTable1_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(ClassifierByLookupTable, "(class-descriptor, descriptor)")
-    {
-        PyTRY
-            PVariable vcl, vvl;
-            PyObject *pyvlist = NULL, *pydlist = NULL;
-            if (!PyArg_ParseTuple(args, "O&O&|OO", cc_Variable, &vcl, cc_Variable, &vvl, &pyvlist, &pydlist))
-                PYERROR(PyExc_TypeError,
-                    "invalid parameter; two variables and, optionally, ValueList and DistributionList expected",
-                     NULL);
+Object construction in Python is divided between two methods. The constructors
+we discussed above construct the essential part of the object - they allocate
+the necessary memory and initialize the fields far enough that the object is
+valid to enter the garbage collection. The second part is handled by the
+``init`` method. It is, however, not forbidden to organize the things so that
+``new`` does all the job. This is also the case in Orange. The only task left
+for ``init`` is to set any attributes that user gave as the keyword arguments to
+the constructor.
 
-            TClassifierByLookupTable1 *cblt = mlnew TClassifierByLookupTable1(vcl, vvl);
-            return initializeTables(pyvlist, pydlist, cblt) ? WrapNewOrange(cblt, type) : NULL;
-        PyCATCH
-    }
+For instance, Python's statement
+``orange.EnumVariable("a", values=["a", "b", "c"])`` is executed so that ``new``
+constructs the variable and gives it the name, while ``init`` sets the
+``values`` field.
 
-Function parses the arguments by calling ``PyArg_ParseTuple``, constructs an instance of ``ClassifierByLookupTable1``, initializes it and returns either the constructed object or NULL which signifies an error. ``PyTRY`` and ``PyCATCH`` catch the possible Orange's exception and turn them into Python exceptions.
-
-Even if the class is defined by ``DATASTRUCTURE``, you can still specify a different constructor, most probably the last form of it (the ``_new`` function). In this case, specify a keyword ``ROOT`` as a parent and pyxtract will understand that this is the base class.
-
-Object construction in Python is divided between two methods. The constructors we discussed above construct the essential part of the object - they allocate the necessary memory and initialize the fields far enough that the object is valid to enter the garbage collection. The second part is handled by the ``init`` method. It is, however, not forbidden to organize the things so that ``new`` does all the job. This is also the case in Orange. The only task left for ``init`` is to set any attributes that user gave as the keyword arguments to the constructor.
-
-For instance, Python's statement ``orange.EnumVariable("a", values=["a", "b", "c"])`` is executed so that ``new`` constructs the variable and gives it the name, while ``init`` sets the ``values`` field. You don't need to do anything about it.
-
-The ``new`` operator, however, sometimes also accepts keyword arguments. For instance, when constructing an ``ExampleTable`` by reading the data from file, you can specify a domain (using keyword argument ``domain``), a list of attributes to reuse if possible (``use``), you can tell it not to reuse the stored domain or not to store the newly constructed domain (``dontCheckStored``, ``dontStore``). After the ``ExampleTable`` is constructed, ``init`` is called to set the attributes. To tell it to ignore the keyword arguments that the constructor might (or had) used, we write the following. ::
+The ``new`` operator can also accept keyword arguments. For
+instance, when constructing an ``ExampleTable`` by reading the data from a file,
+you can specify a domain (using keyword argument ``domain``), a list of
+attributes to reuse if possible (``use``), you can tell it not to reuse the
+stored domain or not to store the newly constructed domain (``dontCheckStored``,
+``dontStore``). After the ``ExampleTable`` is constructed, ``init`` is called to
+set the attributes. To tell it to ignore the keyword arguments that the
+constructor might (or had) used, we write the following. ::
 
     CONSTRUCTOR_KEYWORDS(ExampleTable, "domain use useMetas dontCheckStored dontStore filterMetas")
 
-``init`` will ignore all the keywords from the list.
-
-Talking about attributes, here's another macro. You know you can assign arbitrary attributes to Orange classes. Let ``ba`` be an orange object, say ``orange.BayesLearner``. If you assign new attributes as usual directly, eg. ``ba.myAttribute = 12``, you will get a warning (you should use the object's method ``setattr(name, value)`` to avoid it). Some objects have some attributes that cannot be implemented in C++ code, yet they are usual and useful. For instance, ``Graph`` can use attributes ``objects``, ``forceMapping`` and ``returnIndices``, which can only be set from Python (if you take a look at the documentation on ``Graph`` you will see why these cannot be implemented in C++). Yet, since user are allowed to set these attributes and will do so often, we don't want to give warnings. We achieve this by ::
+There's another macro related to attributes. Let ``ba`` be an orange object, say
+an instance of ``orange.BayesLearner``. If you assign new attributes as usual
+directly, eg. ``ba.myAttribute = 12``, you will get a warning (you should use
+the object's method ``setattr(name, value)`` to avoid it). Some objects have
+some attributes that cannot be implemented in C++ code, yet they are usual and
+useful. For instance, ``Graph`` can use attributes ``objects``, ``forceMapping``
+and ``returnIndices``, which can only be set from Python (if you take a look at
+the documentation on ``Graph`` you will see why these cannot be implemented in
+C++). Yet, since user are allowed to set these attributes and will do so often,
+we don't want to give warnings. We achieve this by ::
 
     RECOGNIZED_ATTRIBUTES(Graph, "objects forceMapping returnIndices")
 
-How do these things function? Well, it is not hard to imagine: pyxtract catches all such exceptions and stores the corresponding lists for each particular class. The ``init`` constructor then checks the list prior to setting attributes. Also the method for setting attributes that issues warnings for unknown attributes checks the list prior to complaining.
-
 
 Special methods
 ===============
 
-Special methods act as the class built-in methods. They define what the type can do: if it, for instance, supports multiplication, it should define the operator that gets the object itself and another object and return the product (or throw an exception). If it allows for indexing, it defines an operator that gets the object itself and the index and returns the element. These operators are low-level; most can be called from Python scripts but they are also internally by Python. For instance, if ``table`` is an ``ExampleTable``, then ``for e in table:`` or ``reduce(f, table)`` will both work by calling the indexing operator for each table's element.
+Special methods act as the class built-in methods. They define what the type can
+do: if it, for instance, supports multiplication, it should define the operator
+that gets the object itself and another object and return the product (or throw
+an exception). If it allows for indexing, it defines an operator that gets the
+object itself and the index, and returns the element. These operators are
+low-level; most can be called from Python scripts but they are also internally
+by Python. For instance, if ``table`` is an ``ExampleTable``, then
+``for e in table:`` or ``reduce(f, table)`` will both work by calling the
+indexing operator for each table's element.
+For more details, consider the Python manual, chapter "Extending and
+Embedding the Python Interpreter" section "Defining New Types".
 
-We shall here avoid the further discussion of this since the topic is adequately described in Python manuals (see "Extending and Embedding the Python Interpreter", chapter 2, "Defining New Types").
+To define a method for Orange class, you need to define a function named,
+``<classname>_<methodname>``; the function should return either
+``PyObject *``, ``int`` or ``void``. The function's head has to be written in a
+single line. Regarding the arguments and the result, it should conform to
+Python's specifications. Pyxtract will detect the methods and set the pointers
+in ``PyTypeObject`` correspondingly.
 
-To define a method for Orange class, you need to define a function named, ``&lt;classname&gt;_&lt;methodname&gt;``; the function should return either ``PyObject *``, ``int`` or ``void``. The function's head has to be written in a single line. Regarding the arguments and the result, it should conform to Python's specifications. Pyxtract will detect the methods and set the pointers in ``PyTypeObject`` correspondingly.
-
-Here's a list of methods: the left column represents a method name that triggers pyxtract (these names generally correspond to special method names of Python classes as a programmer in Python sees them) and the second next is the name of the field in ``PyTypeObject`` or subjugated structures. See Python documentation for description of functions' arguments and results. Not all methods can be directly defined; for those that can't, it is because we either use an alternative method (eg. ``setattro`` instead of ``setattr``) or pyxtract gets or computes the data for this field in some other way. If you really miss something ... wasn't the idea of open source that you are allowed to modify the code (e.g. of pyxtract) yourself?
+Here is a list of methods: the left column represents a method name that
+triggers pyxtract (these names generally correspond to special method names of
+Python classes as a programmer in Python sees them) and the second is the
+name of the field in ``PyTypeObject`` or subjugated structures. See Python
+documentation for description of functions' arguments and results. Not all
+methods can be directly defined; for those that can't, it is because we either
+use an alternative method (eg. ``setattro`` instead of ``setattr``) or pyxtract
+gets or computes the data for this field in some other way.
 
 General methods
 ---------------
 |              |                       | has been taken care of. If you have a brand new object,   |
 |              |                       | copy the code of one of Orange's deallocators.            |
 +--------------+-----------------------+-----------------------------------------------------------+
-| ``.``        | ``tp_print``          | This function can't be redefined as it seem to crash      |
-|              |                       | Python (due to difference in compilers?!)                 |
-+--------------+-----------------------+-----------------------------------------------------------+
 | ``.``        | ``tp_getattr``        | Can't be redefined since we use ``tp_getattro`` instead.  |
 +--------------+-----------------------+-----------------------------------------------------------+
 | ``.``        | ``tp_setattr``        | Can't be redefined since we use ``tp_setattro`` instead.  |
 | ``setitem`` | ``mp_ass_subscript`` |
 +-------------+----------------------+
 
-For example, here's what gets called when you want to know the length of an example table. ::
+For example, here is what gets called when you want to know the length of an
+example table. ::
 
     int ExampleTable_len_sq(PyObject *self)
     {
         PyCATCH_1
     }
 
-``PyTRY`` and ``PyCATCH`` take care of C++ exceptions. ``SELF_AS`` is a macro for casting, ie unwrapping the points (this is an alternative to ``CAST_TO`` you've seen earlier).
+``PyTRY`` and ``PyCATCH`` take care of C++ exceptions. ``SELF_AS`` is a macro
+for casting, ie unwrapping the points (this is an alternative to ``CAST_TO``).
 
 
 Getting and Setting Class Attributes
 ====================================
 
-Exporting of most of C++ class fields is already taken care by the lists that are compiled by pyprops. There are only a few cases in the entire Orange where we needed to manually write specific handlers for setting and getting the attributes. This needs to be done if setting needs some special processing or when simulating an attribute that does not exist in the underlying C++ class.
+Exporting of most of C++ class fields is already taken care by the lists that
+are compiled by pyprops. There are only a few cases in the entire Orange where
+we needed to manually write specific handlers for setting and getting the
+attributes. This needs to be done if setting needs some special processing or
+when simulating an attribute that does not exist in the underlying C++ class.
 
-An example for this is class ``HierarchicalCluster``. It contains results of a general, not necessarily binary clustering, so each node in the tree has a list ``branches`` with all the node's children. Yet, as the usual clustering is binary, it would be nice if the node would also support attributes ``left`` and ``right``. They are not present in C++, but we can write a function that check the number of branches; if there are none, it returns ``None``, if there are more than two, it complains, while otherwise it returns the first branch. ::
+An example for this is class ``HierarchicalCluster``. It contains results of a
+general, not necessarily binary clustering, so each node in the tree has a list
+``branches`` with all the node's children. Yet, as the usual clustering is
+binary, it would be nice if the node would also support attributes ``left`` and
+``right``. They are not present in C++, but we can write a function that check
+the number of branches; if there are none, it returns ``None``, if there are
+more than two, it complains, while otherwise it returns the first branch. ::
 
     PyObject *HierarchicalCluster_get_left(PyObject *self)
     {
         PyCATCH
     }
 
-As you can see from the example, the function needs to accept a ``PyObject *`` (the object it``self``) and return a ``PyObject *`` (the attribute value). The function name needs to be ``&lt;classname&gt;_get_&lt;attributename&gt;``. Setting an attribute is similar; function name should be ``&lt;classname&gt;_set_&lt;attributename&gt;``, it should accept two Python objects (the object and the attribute value) and return an ``int``, where 0 signifies success and -1 a failure.
+As you can see from the example, the function needs to accept a ``PyObject *``
+(the object it``self``) and return a ``PyObject *`` (the attribute value). The
+function name needs to be ``<classname>_get_<attributename>``.
+Setting an attribute is similar; function name should be
+``<classname>_set_<attributename>``, it should accept two Python
+objects (the object and the attribute value) and return an ``int``, where 0
+signifies success and -1 a failure.
 
-If you define only one of the two handlers, you'll get a read-only or write-only attribute.
+If you define only one of the two handlers, you'll get a read-only or write-only
+attribute.
 
 
 Member functions
 ================
 
-You've already seen an example of a member function - the ``ExampleTable``'s method ``sort``. The general template is ``PyObject *&lt;classname&gt;_&lt;methodname&gt;(&lt;arguments&gt;) PYARGS(&lt;arguments-keyword&gt;, &lt;documentation-string&gt;)``. In the case of the ``ExampleTable``'s ``sort``, this looks like this. ::
+We have already shown an example of a member function - the ``ExampleTable``'s
+method ``sort``. The general template is
+``PyObject *<classname>_<methodname>(<arguments>) PYARGS(<arguments-keyword>, <documentation-string>)``.
+In the case of the ``ExampleTable``'s ``sort``, this looks like this. ::
 
     PyObject *ExampleTable_sort(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "() -> None")
 
-Argument type can be any of the usual Python constants stating the number and the kind of arguments, such as ``METH_VARARGS`` or ``METH_O`` - this constant gets copied to the corresponding list (browse Python documentation for ``PyMethodDef``).
+Argument type can be any of the usual Python constants stating the number and
+the kind of arguments, such as ``METH_VARARGS`` or ``METH_O`` - this constant
+gets copied to the corresponding list (browse Python documentation for
+``PyMethodDef``).
 
-If you want more examples, just search Orange's files for the keyword ``PYARGS``.
 
 Class constants
 ===============
 
-Orange classes, as seen from Python, can also have constants, such as ``orange.Classifier.GetBoth``. Classifier's ``GetBoth`` is visible as a member of the class, the derived classes and all their instances (eg. ``BayesClassifier.GetBoth`` and ``bayes.GetBoth``).
+Orange classes, as seen from Python, can also have constants, such as
+``orange.Classifier.GetBoth``. Classifier's ``GetBoth`` is visible as a member
+of the class, the derived classes and all their instances (eg.
+``BayesClassifier.GetBoth`` and ``bayes.GetBoth``).
 
-There are several ways to define such constants. If they are simple integers or floats, you can use ``PYCLASSCONSTANT_INT`` or ``PYCLASSCONSTANT_FLOAT``, like in ::
+There are several ways to define such constants. If they are simple integers or
+floats, you can use ``PYCLASSCONSTANT_INT`` or ``PYCLASSCONSTANT_FLOAT``, like
+in ::
 
     PYCLASSCONSTANT_INT(Classifier, GetBoth, 2)
 
 
     PYCLASSCONSTANT_INT(C45TreeNode, Leaf, TC45TreeNode::Leaf)
 
-Pyxtract will convert the given constant to a Python object (using ``PyInt_FromLong`` or ``PyFloat_FromDouble>``).
+Pyxtract will convert the given constant to a Python object (using
+``PyInt_FromLong`` or ``PyFloat_FromDouble>``).
 
-When the constant is an object of some other type, use ``PYCLASSCONSTANT``. In this form (not used in Orange so far), the third argument can be either an instance of ``PyObject *`` or a function call. In either case, the object or function must be known at the point where the pyxtract generated file is included.
+When the constant is an object of some other type, use ``PYCLASSCONSTANT``. In
+this form (not used in Orange so far), the third argument can be either an
+instance of ``PyObject *`` or a function call. In either case, the object or
+function must be known at the point where the pyxtract generated file is
+included.
 
 
 Pickling
 ========
 
-Pickling is taken care of automatically if the class provides a Python constructor which can construct the object without arguments (it may *accept* arguments, but should be able to do without them. If there is no such constructor, the class should provide a ``__reduce__`` method or it should explicitly declare that it cannot be pickled. If it doesn't pyxtract will issue a warning that the class will not be picklable.
+Pickling is taken care of automatically if the class provides a Python
+constructor that can construct the object without arguments (it may *accept*
+arguments, but should be able to do without them. If there is no such
+constructor, the class should provide a ``__reduce__`` method or it should
+explicitly declare that it cannot be pickled. If it doesn't pyxtract will issue
+a warning that the class will not be picklable.
 
 Here are the rules:
 
 * Classes that provide a ``__reduce__`` method (details follow below) are pickled through that method.
+
 * Class ``Orange``, the base class, already provides a ``__reduce__`` method, which is only useful if the constructor accepts empty arguments. So, if the constructor is declared as ``C_NAMED``, ``C_UNNAMED``, ``C_CALL`` or ``C_CALL3``, the class is the class will be picklable. See the warning below.
+
 * If the constructor is defined by ``_new`` method, and the ``BASED_ON`` definition is followed be ``ALLOWS_EMPTY``, this signifies that it accepts empty arguments, so it will be picklable just as in the above point. For example, the constructor for the class ``DefaultClassifier`` is defined like this ::
 
     PyObject *DefaultClassifier_new(PyTypeObject *tpe, PyObject *args)
         BASED_ON(Classifier, "([defaultVal])") ALLOWS_EMPTY
-  and is picklable through code ``Orange.__reduce__``. But again, see the warning below.
+
+and is picklable through code ``Orange.__reduce__``. But again, see the warning
+below.
 
 * If the constructor is defined as ``ABSTRACT``, there cannot be any instances of this class, so pyxtract will give no warning that it is not picklable.
 * The class can be explicitly defined as not picklable by ``NO_PICKLE`` macro, as in ::
 
     NO_PICKLE(TabDelimExampleGenerator)
-  Such classes won't be picklable even if they define the appropriate constructors. This effectively defined a ``__reduce__`` method which yields an exception; if you manually provide a ``__reduce__`` method for such a class, pyxtract will detect that the method is multiply defined.
-* If there are no suitable constructors, no ``__reduce__`` method and no ``ABSTRACT`` or ``NO_PICKLE`` flag, pyxtract will warn you about that.
 
-When the constructor is used, as in points 2 and 3, pickling will only work if all fields of the C++ class can be set "manually" from Python, are set through the constructor, or are set when assigning other fields (search the source code for the ``afterSet`` method). In other words, if there are fields that are not marked as ``//P`` for pyprops, you will most probably need to manually define a ``__reduce__`` method, as in point 1.
+  Such classes won't be picklable even if they define the appropriate
+  constructors. This effectively defined a ``__reduce__`` method which yields an
+  exception; if you manually provide a ``__reduce__`` method for such a class,
+  pyxtract will detect that the method is multiply defined.
 
-The details of what the ``__reduce__`` method must do are described in the Python documentation. In our circumstances it can be implemented in two ways which differ in what function is used for unpickling: it can either use the class' constructor or we can define a special method for unpickling.
+* If there are no suitable constructors, no ``__reduce__`` method and no
+  ``ABSTRACT`` or ``NO_PICKLE`` flag, pyxtract gives a warning about that.
 
-The former usually happens when the class has a read-only property (``//PR``) which is set by the constructor. For instance, ``AssociationRule`` has read-only fields ``left`` and ``right``, which are needs to be given to the constructor. This is the ``__reduce__`` method for the class. ::
+When the constructor is used, as in points 2 and 3, pickling will only work if
+all fields of the C++ class can be set "manually" from Python, are set through
+the constructor, or are set when assigning other fields. In other words, if
+there are fields that are not
+marked as ``//P`` for pyprops, you will most probably need to manually define
+a ``__reduce__`` method, as in point 1.
+
+The details of what the ``__reduce__`` method must do are described in the
+Python documentation. In our circumstances, it can be implemented in two ways
+which differ in what function is used for unpickling: it can either use the
+class' constructor or we can define a special method for unpickling.
+
+The former usually happens when the class has a read-only property (``//PR``),
+which is set by the constructor. For instance, ``AssociationRule`` has read-only
+fields ``left`` and ``right``, which are needs to be given to the constructor.
+This is the ``__reduce__`` method for the class. ::
 
     PyObject *AssociationRule__reduce__(PyObject *self)
     {
         PyCATCH
     }
 
-As you can learn from the Python documentation, the ``__reduce__`` should return the tuple in which the first element is the function that will do the unpickling, and the second argument are the arguments for that function. Our unpickling function is simply the classes' type (calling a type corresponds to calling a constructor) and the arguments for the constructor are the left- and right-hand side of the rule. The third element of the tuple is classes' dictionary.
+As described in the Python documentation, the ``__reduce__`` should return a
+tuple in which the first element is the function that will do the unpickling,
+and the second argument are the arguments for that function. Our unpickling
+function is simply the classes' type (calling a type corresponds to calling a
+constructor) and the arguments for the constructor are the left- and right-hand
+side of the rule. The third element of the tuple is classes' dictionary.
 
-When unpickling is more complicated, usually when the class has no constructor and contains fields of type ``float *`` or similar, we need a special unpickling function. The function needs to be directly in the modules' namespace (it cannot be a static method of a class), so we named them ``__pickleLoader&lt;classname&gt;``. Search for examples of such functions in the source code; note that the instance's true class need to be pickled, too. Also, check how we use ``TCharBuffer`` throughout the code to store and pickle binary data as Python strings.
+When unpickling is more complicated - usually when the class has no constructor
+and contains fields of type ``float *`` or similar - we need a special
+unpickling function. The function needs to be directly in the modules' namespace
+(it cannot be a static method of a class), so we named them
+``__pickleLoader<classname>``. Search for examples of such functions in
+the source code; note that the instance's true class need to be pickled, too.
+Also, check how we use ``TCharBuffer`` throughout the code to store and pickle
+binary data as Python strings.
 
-Be careful when manually writing the unpickler: if a C++ class derived from that class inherits its ``__reduce__``, the corresponding unpickler will construct an instance of a wrong class (unless the unpickler functions through Python's constructor, ``ob_type->tp_new``). Hence, classes derived from a class which defines an unpickler have to define their own ``__reduce__``, too.
+Be careful when manually writing the unpickler: if a C++ class derived from that
+class inherits its ``__reduce__``, the corresponding unpickler will construct an
+instance of a wrong class (unless the unpickler functions through Python's
+constructor, ``ob_type->tp_new``). Hence, classes derived from a class which
+defines an unpickler have to define their own ``__reduce__``, too.
 
 Non-member functions and constants
 ==================================
 
-Most Orange's functions are members of classes. About the only often used exception to this is ``orange.newmetaid`` which returns a new ID for a meta attribute. These functions are defined in the same way as member function except that the function name doesn't have the class name (and the underscore - that's how pyxtract distinguishes between the two). Here's the ``newmetaid`` function. ::
+Non-member functions are defined in the same way as member functions except
+that their names do not start with the class name. Here is how the ``newmetaid``
+is implemented ::
 
     PyObject *newmetaid(PyObject *, PyObject *) PYARGS(0,"() -> int")
     {
         PyCATCH
     }
 
-Orange also defines some non-member constants. These are defined in a similar fashion as the class constants. ``PYCONSTANT_INT(&lt;constant-name&gt;, &lt;integer&gt;)`` defines an integer constant and ``PYCONSTANT_FLOAT`` would be used for a continuous one. ``PYCONSTANT`` is used for objects of other types, as the below example that defines an (obsolete) constant ``MeasureAttribute_splitGain`` shows. ::
+Orange also defines some non-member constants. These are defined in a similar
+fashion as the class constants.
+``PYCONSTANT_INT(<constant-name>, <integer>)`` defines an integer
+constant and ``PYCONSTANT_FLOAT`` would be used for a continuous one.
+``PYCONSTANT`` is used for objects of other types, as the below example that
+defines an (obsolete) constant ``MeasureAttribute_splitGain`` shows. ::
 
     PYCONSTANT(MeasureAttribute_splitGain, (PyObject *)&PyOrMeasureAttribute_gainRatio_Type)
 
-Class constants from the previous chapter are put in a pyxtract generated file that is included at the end of the file in which the constant definitions and the corresponding classes are. Global constant modules are included in an other file, far away from their actual definitions. For this reason, ``PYCONSTANT`` cannot reference any functions (the above example is an exception - all class types are declared in this same file and are thus available at the moment the above code is used). Therefore, if the constant is defined by a function call, you need to use another keyword, ``PYCONSTANTFUNC``::
+Class constants from the previous section are put in a pyxtract generated file
+that is included at the end of the file in which the constant definitions and
+the corresponding classes are. Global constant modules are included in another
+file, far away from their actual definitions. For this reason, ``PYCONSTANT``
+cannot refer to any functions (the above example is an exception - all class
+types are declared in this same file and are thus available at the moment the
+above code is used). Therefore, if the constant is defined by a function call,
+you need to use another keyword, ``PYCONSTANTFUNC``::
 
     PYCONSTANTFUNC(globalRandom, stdRandomGenerator)
 
-Pyxtract will generate a code which will, prior to calling ``stdRandomGenerator``, declare it as a function with no arguments that returns ``PyObject *``. Of course, you will have to define the function somewhere in your code, like this::
+Pyxtract will generate a code which will, prior to calling
+``stdRandomGenerator``, declare it as a function with no arguments that returns
+``PyObject *``. Of course, you will have to define the function somewhere in
+your code, like this::
 
     PyObject *stdRandomGenerator()
     {
         return WrapOrange(globalRandom);
     }
 
-Another example are ``VarTypes``. You've probably already used ``orange.VarTypes.Discrete`` and ``orange.VarTypes.Continuous`` to check an attribute's type. ``VarTypes`` is a tiny module inside Orange that contains nothing but five constants, representing various attribute types. From pyxtract perspective, ``VarTypes`` is a constant. Here's the complete definition. ::
+Another example are ``VarTypes``. ``VarTypes`` is a tiny module inside Orange
+that contains nothing but five constants, representing various attribute types.
+From pyxtract perspective, ``VarTypes`` is a constant. This is the complete
+definition. ::
 
     PyObject *VarTypes()
     {
 
     PYCONSTANTFUNC(VarTypes, VarTypes)
 
-If you want to understand the constants completely, check the Orange's pyxtract generated file initialization.px.
+If you want to understand the constants completely, check the Orange's pyxtract
+generated file initialization.px.
 
 How does it all fit together
 ============================
 
-This part of the text's main purpose is to remind the pyxtract author of the structure of the files pyxtract creates. (I'm annoyed when I don't know how my programs work. And I happen to be annoyed quite frequently. :-) If you think you can profit from reading it, you are welcome.
+We will finish the section with a description of the files generated by the two
+scripts. Understanding these may be needed for debugging purposes.
 
 File specific px files
 ----------------------
 
-For each compiled cpp file, pyxtract creates a px file with the same name. The file starts with externs declaring the base classes for the classes whose types are defined later on.
+For each compiled cpp file, pyxtract creates a px file with the same name. The
+file starts with externs declaring the base classes for the classes whose types
+are defined later on. Then follow class type definitions:
 
-Then follow class type definitions.
+* Method definitions (``PyMethodDef``). Nothing exotic here, just a table with
+  the member functions that is pointed to by ``tp_methods`` of the
+  ``PyTypeObject``.
 
-* Method definitions (``PyMethodDef``). Nothing exotic here, just a table with the member functions that is pointed to by ``tp_methods`` of the ``PyTypeObject``.
-
-* GetSet definitions (``PyGetSetDef``). Similar to methods, a list to be pointed to by ``tp_getset``, which includes the attributes for which special handlers were written.
+* GetSet definitions (``PyGetSetDef``). Similar to methods, a list to be pointed
+  to by ``tp_getset``, which includes the attributes for which special handlers
+  were written.
 
 * Definitions of doc strings for call operator and constructor.
 
-* Constants. If the class has any constants, there will be a function named ``void &lt;class-name&gt;_addConstants()``. The function will create a class dictionary in the type's ``tp_dict``, if there is none yet. Then it will store the constants in it. The functions is called at the module initialization, file initialization.px.
+* Constants. If the class has any constants, there will be a function named
+  ``void <class-name>_addConstants()``. The function will create a class
+  dictionary in the type's ``tp_dict``, if there is none yet. Then it will store
+  the constants in it. The functions is called at the module initialization,
+  file initialization.px.
 
-* Constructors. If the class uses generic constructors (ie, if it's defined by ``C_UNNAMED``, ``C_NAMED``, ``C_CALL`` or ``C_CALL3``), they will need to call a default object constructor, like the below one for ``FloatVariable``. (This supposes the object is derived from ``TOrange``! We will need to get rid of this we want pyxtract to be more general. Maybe an additional argument in ``DATASTRUCTURE``?) ::
+* Constructors. If the class uses generic constructors (ie, if it's defined by
+  ``C_UNNAMED``, ``C_NAMED``, ``C_CALL`` or ``C_CALL3``), they will need to call
+  a default object constructor, like the below one for ``FloatVariable``.
+  (This supposes the object is derived from ``TOrange``! We will need to get rid
+  of this we want pyxtract to be more general. Maybe an additional argument in
+  ``DATASTRUCTURE``?) ::
 
     POrange FloatVariable_default_constructor(PyTypeObject *type)
     {
         return POrange(mlnew TFloatVariable(), type);
     }
-  If the class is abstract, pyxtract defines a constructor that will call ``PyOrType_GenericAbstract``. ``PyOrType_GenericAbstract`` checks the type that the caller wishes to construct; if it is a type derived from this type, it permits it, otherwise it complains that the class is abstract.
+
+  If the class is abstract, pyxtract defines a constructor that will call
+  ``PyOrType_GenericAbstract``. ``PyOrType_GenericAbstract`` checks the type
+  that the caller wishes to construct; if it is a type derived from this type,
+  it permits it, otherwise it complains that the class is abstract.
 
 * Aliases. A list of renamed attributes.
 
-* ``PyTypeObject`` and the numeric, sequence and mapping protocols. ``PyTypeObject`` is named ``PyOr&lt;classname&gt;_Type_inh``.
+* ``PyTypeObject`` and the numeric, sequence and mapping protocols.
+  ``PyTypeObject`` is named ``PyOr<classname>_Type_inh``.
 
-* Definition of conversion functions. This is done by macro ``DEFINE_cc(&lt;classname&gt;)`` which defines ``int ccn_&lt;classname&gt;(PyObject *obj, void *ptr)`` - functions that can be used in ``PyArg_ParseTuple`` for converting an argument (given as ``PyObject *`` to an instance of ``&lt;classname&gt;``. Nothing needs to be programmed for the conversion, it is just a cast: ``*(GCPtr< T##type > *)(ptr) = PyOrange_As##type(obj);``). The difference between ``cc`` and ``ccn`` is that the latter accepts null pointers.
+* Definition of conversion functions. This is done by macro
+  ``DEFINE_cc(<classname>)`` which defines
+  ``int ccn_<classname>(PyObject *obj, void *ptr)`` - functions that can
+  be used in ``PyArg_ParseTuple`` for converting an argument (given as
+  ``PyObject *`` to an instance of ``<classname>``. Nothing needs to be
+  programmed for the conversion, it is just a
+  cast: ``*(GCPtr< T##type > *)(ptr) = PyOrange_As##type(obj);``). The
+  difference between ``cc`` and ``ccn`` is that the latter accepts null
+  pointers.
 
-* ``TOrangeType``. Although ``PyTypeObject`` is a regular Python object, it unfortunately isn't possible to derive new objects from it. Obviously the developers of Python didn't think anyone would need it, and this part of Python's code is messy enough even without it. Orange nevertheless uses a type ``TOrangeType`` that begins with ``PyTypeObject`` (essentially inheriting it). The new definition also includes the RTTI used for wrapping (this way Orange nows which C++ class corresponds to which Python class), a pointer to the default constructor (used by generic constructors), a pointer to list of constructor keywords (``CONSTRUCTOR_KEYWORDS``, keyword arguments that should be ignored in a later call to ``init``) and recognized attributes (``RECOGNIZED_ATTRIBUTES``, attributes that don't yield warnings when set), a list of aliases, and pointers to ``cc_`` and ``ccn_`` functions. The latter are not used by Orange, since it can call the converters directly. They are here because ``TOrangeType`` is exported in a DLL while ``cc_`` and ``ccn_`` are not (for the sake of limiting the number of exported symbols).
+* ``TOrangeType`` that (essentially) inherits ``PyTypeObject``. The new
+  definition also includes the RTTI used for wrapping (this way Orange knows
+  which C++ class corresponds to which Python class), a pointer to the default
+  constructor (used by generic constructors), a pointer to list of constructor
+  keywords (``CONSTRUCTOR_KEYWORDS``, keyword arguments that should be ignored
+  in a later call to ``init``) and recognized attributes
+  (``RECOGNIZED_ATTRIBUTES``, attributes that don't yield warnings when set), a
+  list of aliases, and pointers to ``cc_`` and ``ccn_`` functions. The latter
+  are not used by Orange, since it can call the converters directly. They are
+  here because ``TOrangeType`` is exported in a DLL while ``cc_`` and ``ccn_``
+  are not (for the sake of limiting the number of exported symbols).
 
 
 initialization.px
 
 Initialization.px defines the global module stuff.
 
-First, here is a list of all ``TOrangeTypes``. The list is used for checking whether some Python object is of Orange's type or derived from one, for finding a Python class corresponding to a C++ class (based on C++'s RTTI). Orange also exports the list as ``orange._orangeClasses``; this is a ``PyCObject`` so it can only be used by other Python extensions written in C.
+First, here is a list of all ``TOrangeTypes``. The list is used for checking
+whether some Python object is of Orange's type or derived from one, for finding
+a Python class corresponding to a C++ class (based on C++'s RTTI). Orange also
+exports the list as ``orange._orangeClasses``; this is a ``PyCObject`` so it can
+only be used by other Python extensions written in C.
 
-Then come declarations of all non-member functions, followed by a ``PyMethodDef`` structure with them.
+Then come declarations of all non-member functions, followed by a
+``PyMethodDef`` structure with them.
 
-Finally, here are declarations of functions that return manually constructed constants (eg ``VarTypes``) and declarations of functions that add class constants (eg ``Classifier_addConstants``). The latter functions were generated by pyxtract and reside in the individual px files. Then follows a function that calls all the constant related functions declared above. This function also adds all class types to the Orange module. Why not in a loop over ``orangeClasses``?
+Finally, here are declarations of functions that return manually constructed
+constants (eg ``VarTypes``) and declarations of functions that add class
+constants (eg ``Classifier_addConstants``). The latter functions were generated
+by pyxtract and reside in the individual px files. Then follows a function that
+calls all the constant related functions declared above. This function also adds
+all class types to the Orange module.
 
 The main module now only needs to call ``addConstants``.
 
     int ccn_Domain(PyObject *, void *);
     #define PyOrange_AsDomain(op) (GCPtr< TDomain >(PyOrange_AS_Orange(op)))
 
-*****************
-Where to include?
-*****************
+**************************
+What and where to include?
+**************************
 
-As already mentioned, ppp files should be included (at the beginning) of the corresponding cpp files, instead of the hpp file. For instance, domain.ppp is included in domain.cpp. Each ppp should be compiled only once, all other files needing the definition of ``TDomain`` should still include domain.hpp as usual.
+As already mentioned, ppp files should be included (at the beginning) of the
+corresponding cpp files, instead of the hpp file. For instance, domain.ppp is
+included in domain.cpp. Each ppp should be compiled only once, all other files
+needing the definition of ``TDomain`` should still include domain.hpp as usual.
 
-File-specific px files are included in the corresponding cpp files. lib_kernel.px is included at the end of lib_kernel.cpp, from which it was generated. initialization.px should preferably be included in the file that initializes the module (function ``initorange`` needs to call ``addConstants``, which is declared in initialization.px. These px files contain definitions and must be compiled only once. externs.px contains declarations and can be included wherever needed.
+File-specific px files are included in the corresponding cpp files.
+lib_kernel.px is included at the end of lib_kernel.cpp, from which it was
+generated. initialization.px should preferably be included in the file that
+initializes the module (function ``initorange`` needs to call ``addConstants``,
+which is declared in initialization.px. These px files contain definitions and
+must be compiled only once. externs.px contains declarations and can be included
+wherever needed.
 
-Some steps in these instructions are only for Visual Studio 6.0. If you use a newer version of Visual Studio or if you use Linux, adapt them.
+For Microsoft Visual Studio, create a new, blank workspace. Specify the
+directory with orange sources as "Location". Add a new project of type "Win 32
+Dynamic-Link Library"; change the
+location back to d:\ai\orange\source. Make it an empty DLL project.
 
-Create a new, blank workspace. If your orange sources are in d:\ai\orange\source (as are mine :), specify this directory as a "Location". Add a new project of type "Win 32 Dynamic-Link Library"; change the location back to d:\ai\orange\source. Make it an empty DLL project.
-
-Whatever names you give your module, make sure that the .cpp and .hpp files you create as you go on are in orange\source\something (replace "something" with something), since the further instructions will suppose it.
+Whatever names you give your module, make sure that the .cpp and .hpp files you
+create as you go on are in orange\source\something (replace "something" with
+something), since the further instructions will suppose it.

docs/extend-widgets/rst/DataSamplerA.svg

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 48 48">
+	<metadata>
+		<rdf:RDF>
+			<cc:Work rdf:about="">
+				<dc:format>image/svg+xml</dc:format>
+				<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+				<dc:title/>
+			</cc:Work>
+		</rdf:RDF>
+	</metadata>
+	<path d="m24,10.5a12.5,11,0,1,1,-25,0,12.5,11,0,1,1,25,0z" transform="translate(3.5,2.5)" stroke="#39394c" stroke-dasharray="none" stroke-miterlimit="4" stroke-width="1.7" fill="none"/>
+	<path d="m24.5,10.5a13,11,0,1,1,-26,0,13,11,0,1,1,26,0z" transform="translate(20.893908,24.5)" stroke="#39394c" stroke-dasharray="none" stroke-miterlimit="4" stroke-width="1.7" fill="none"/>
+	<path stroke-linejoin="round" d="m30,10,10,0,1,0,0,9,3-1-4,4-4-4,3,1,0-7-9,0z" stroke="#2b2827" stroke-linecap="butt" stroke-miterlimit="4" stroke-dasharray="none" stroke-width="1.5" fill="none"/>
+	<path stroke-linejoin="miter" d="M10,9,8,7m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="M19,8,17,6m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m15,14-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="M9,17,7,15m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m21,17-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m27,33-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m38,36-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<text style="writing-mode:lr;letter-spacing:0px;text-anchor:start;word-spacing:0px;text-align:start;" font-weight="bold" xml:space="preserve" font-size="10px" font-style="normal" font-stretch="normal" font-variant="normal" y="44" x="4" font-family="Sans" line-height="125%" fill="#000000"><tspan x="4" y="44">A</tspan></text>
+</svg>

docs/extend-widgets/rst/DataSamplerB.png

Removed
Old image

docs/extend-widgets/rst/DataSamplerB.svg

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 48 48">
+	<metadata>
+		<rdf:RDF>
+			<cc:Work rdf:about="">
+				<dc:format>image/svg+xml</dc:format>
+				<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+				<dc:title/>
+			</cc:Work>
+		</rdf:RDF>
+	</metadata>
+	<path d="m24,10.5a12.5,11,0,1,1,-25,0,12.5,11,0,1,1,25,0z" transform="translate(3.5,2.5)" stroke="#39394c" stroke-dasharray="none" stroke-miterlimit="4" stroke-width="1.7" fill="none"/>
+	<path d="m24.5,10.5a13,11,0,1,1,-26,0,13,11,0,1,1,26,0z" transform="translate(20.893908,24.5)" stroke="#39394c" stroke-dasharray="none" stroke-miterlimit="4" stroke-width="1.7" fill="none"/>
+	<path stroke-linejoin="round" d="m30,10,10,0,1,0,0,9,3-1-4,4-4-4,3,1,0-7-9,0z" stroke="#2b2827" stroke-linecap="butt" stroke-miterlimit="4" stroke-dasharray="none" stroke-width="1.5" fill="none"/>
+	<path stroke-linejoin="miter" d="M10,9,8,7m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="M19,8,17,6m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m15,14-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="M9,17,7,15m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m21,17-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m27,33-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m38,36-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<text style="writing-mode:lr-tb;letter-spacing:0px;text-anchor:start;word-spacing:0px;text-align:start;" font-weight="bold" xml:space="preserve" font-size="10px" font-style="normal" font-stretch="normal" font-variant="normal" y="44" x="4" font-family="Sans" line-height="125%" fill="#000000"><tspan x="4" y="44">B</tspan></text>
+</svg>

docs/extend-widgets/rst/DataSamplerC.svg

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 48 48">
+	<metadata>
+		<rdf:RDF>
+			<cc:Work rdf:about="">
+				<dc:format>image/svg+xml</dc:format>
+				<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+				<dc:title/>
+			</cc:Work>
+		</rdf:RDF>
+	</metadata>
+	<path d="m24,10.5a12.5,11,0,1,1,-25,0,12.5,11,0,1,1,25,0z" transform="translate(3.5,2.5)" stroke="#39394c" stroke-dasharray="none" stroke-miterlimit="4" stroke-width="1.7" fill="none"/>
+	<path d="m24.5,10.5a13,11,0,1,1,-26,0,13,11,0,1,1,26,0z" transform="translate(20.893908,24.5)" stroke="#39394c" stroke-dasharray="none" stroke-miterlimit="4" stroke-width="1.7" fill="none"/>
+	<path stroke-linejoin="round" d="m30,10,10,0,1,0,0,9,3-1-4,4-4-4,3,1,0-7-9,0z" stroke="#2b2827" stroke-linecap="butt" stroke-miterlimit="4" stroke-dasharray="none" stroke-width="1.5" fill="none"/>
+	<path stroke-linejoin="miter" d="M10,9,8,7m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="M19,8,17,6m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m15,14-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="M9,17,7,15m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m21,17-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m27,33-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<path stroke-linejoin="miter" d="m38,36-2-2m2,2-2,2m4-4-2,2,2,2" stroke="#252b2d" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+	<text style="writing-mode:lr-tb;letter-spacing:0px;text-anchor:start;word-spacing:0px;text-align:start;" font-weight="bold" xml:space="preserve" font-size="10px" font-style="normal" font-stretch="normal" font-variant="normal" y="44" x="4" font-family="Sans" line-height="125%" fill="#000000"><tspan x="4" y="44">C</tspan></text>
+</svg>

docs/extend-widgets/rst/LearningCurve.svg

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 48 48">
+	<g style="writing-mode:lr-tb;letter-spacing:0px;text-anchor:start;word-spacing:0px;text-align:start;" line-height="125%" font-weight="bold" font-size="12px" transform="matrix(1,0,0,1.2314815,0.479353,-5.883444)" font-stretch="normal" font-variant="normal" font-style="normal" font-family="Sans" fill="#707070">
+		<path d="m10.956,31.463c-0.27849,0.000004-0.49422,0.12909-0.64718,0.38727-0.15298,0.25402-0.22946,0.61838-0.22946,1.0931-0.000009,0.47888,0.07451,0.84741,0.22357,1.1056,0.15296,0.25402,0.37065,0.38102,0.65307,0.38102,0.2824,0.000001,0.49813-0.12701,0.64719-0.38102,0.14904-0.25818,0.22356-0.62671,0.22357-1.1056-0.00001-0.47471-0.07649-0.83908-0.22946-1.0931-0.14906-0.25818-0.36282-0.38726-0.6413-0.38727m0-1.0494c0.72954,0.000004,1.3042,0.22487,1.7239,0.6746,0.41968,0.44973,0.62952,1.0681,0.62954,1.8551-0.000011,0.78703-0.20986,1.4096-0.62954,1.8676-0.4197,0.4539-0.99432,0.68084-1.7239,0.68084-0.72956,0-1.3061-0.22695-1.7297-0.68084-0.4197-0.45806-0.62954-1.0806-0.62953-1.8676-0.000007-0.78286,0.20984-1.3992,0.62953-1.8489,0.4236-0.45389,1.0002-0.68084,1.7297-0.68084m-5.3952,5.0782-1.3003,0,5.4893-9.6755,1.3061,0-5.4952,9.6755m-1.2061-9.6755c0.72955,0.000009,1.3022,0.22696,1.718,0.68084,0.41969,0.44974,0.62953,1.0681,0.62953,1.8551-0.000005,0.78704-0.20985,1.4075-0.62953,1.8614-0.41577,0.4539-0.98843,0.68085-1.718,0.68084-0.72956,0.000004-1.3042-0.22694-1.7239-0.68084-0.41577-0.45389-0.62365-1.0744-0.62365-1.8614-3E-7-0.78702,0.20788-1.4054,0.62365-1.8551,0.41969-0.45388,0.99431-0.68083,1.7239-0.68084m0,1.0494c-0.28241,0.00001-0.5001,0.1291-0.65307,0.38727-0.15297,0.25819-0.22946,0.62464-0.22946,1.0993-0.000001,0.47889,0.076484,0.8495,0.22946,1.1118,0.15297,0.25818,0.37066,0.38727,0.65307,0.38727,0.28241,0.000007,0.49813-0.12908,0.64719-0.38727,0.15297-0.26234,0.22945-0.63295,0.22946-1.1118-0.000004-0.47471-0.076494-0.84116-0.22946-1.0993-0.15297-0.25817-0.3687-0.38726-0.64719-0.38727"/>
+		<path d="m25.834,33.719c-0.31454,0.000006-0.55818,0.17814-0.73094,0.53442-0.17278,0.35054-0.25916,0.85336-0.25915,1.5085-0.00001,0.66085,0.08415,1.1694,0.25251,1.5257,0.17276,0.35054,0.41862,0.52581,0.73759,0.5258,0.31895,0.000001,0.56259-0.17527,0.73094-0.5258,0.16833-0.35628,0.2525-0.86484,0.25251-1.5257-0.000011-0.6551-0.08639-1.1579-0.25915-1.5085-0.16835-0.35628-0.40978-0.53442-0.7243-0.53442m0-1.4481c0.82396,0.000007,1.4729,0.31032,1.947,0.93093,0.47399,0.62063,0.71099,1.474,0.71101,2.5601-0.000013,1.0861-0.23702,1.9452-0.71101,2.5773-0.47402,0.62637-1.123,0.93955-1.947,0.93955-0.82398,0-1.4752-0.31318-1.9536-0.93955-0.47401-0.63211-0.71102-1.4912-0.71101-2.5773-0.000008-1.0803,0.23699-1.9308,0.71101-2.5514,0.47842-0.62636,1.1296-0.93954,1.9536-0.93955m-6.0934,7.0079-1.4685,0,6.1997-13.352,1.4752,0-6.2064,13.352m-1.3622-13.352c0.82397,0.000015,1.4707,0.3132,1.9403,0.93955,0.474,0.62064,0.711,1.474,0.71101,2.5601-0.000006,1.0861-0.23701,1.9423-0.71101,2.5687-0.46958,0.62637-1.1164,0.93956-1.9403,0.93955-0.82397,0.000005-1.473-0.31318-1.947-0.93955-0.46958-0.62636-0.70436-1.4826-0.70436-2.5687s0.23479-1.9394,0.70436-2.5601c0.474-0.62635,1.123-0.93954,1.947-0.93955m0,1.4481c-0.31896,0.000011-0.56482,0.17815-0.73759,0.53442-0.17277,0.35629-0.25915,0.86198-0.25915,1.5171-0.000001,0.66086,0.08638,1.1723,0.25915,1.5343,0.17277,0.35629,0.41863,0.53443,0.73759,0.53442,0.31895,0.00001,0.5626-0.17813,0.73094-0.53442,0.17276-0.36202,0.25915-0.87346,0.25915-1.5343-0.000005-0.65509-0.08639-1.1608-0.25915-1.5171-0.17277-0.35627-0.41642-0.53441-0.73094-0.53442"/>
+		<path d="m42.439,35.057c-0.36705,0.000006-0.65138,0.20974-0.85298,0.62919-0.20162,0.4127-0.30243,1.0047-0.30242,1.7759-0.000012,0.77804,0.0982,1.3768,0.29467,1.7962,0.2016,0.4127,0.48851,0.61905,0.86074,0.61904,0.3722,0.000003,0.65652-0.20634,0.85298-0.61904,0.19643-0.41946,0.29465-1.0182,0.29467-1.7962-0.000013-0.77126-0.10081-1.3632-0.30242-1.7759-0.198-0.419-0.48-0.629-0.847-0.629m0-1.7049c0.96153,0.000007,1.7189,0.36534,2.272,1.096,0.55313,0.73068,0.8297,1.7354,0.82972,3.014-0.000015,1.2787-0.27659,2.2901-0.82972,3.0343-0.55316,0.73744-1.3105,1.1062-2.272,1.1062-0.96155,0-1.7215-0.36872-2.2798-1.1062-0.55316-0.7442-0.82973-1.7556-0.82972-3.0343-0.000009-1.2719,0.27656-2.2732,0.82972-3.0039,0.5583-0.73743,1.3182-1.1062,2.2798-1.1062m-7.1108,8.2505-1.7137,0,7.2348-15.72,1.7215,0-7.2426,15.72m-1.588-15.719c0.96154,0.000017,1.7163,0.36874,2.2643,1.1062,0.55314,0.73069,0.82971,1.7354,0.82972,3.014-0.000007,1.2787-0.27658,2.2868-0.82972,3.0242-0.54798,0.73745-1.3027,1.1062-2.2643,1.1062-0.96154,0.000006-1.7189-0.36871-2.272-1.1062-0.54798-0.73743-0.82196-1.7455-0.82196-3.0242s0.27399-2.2833,0.82196-3.014c0.55314-0.73742,1.3105-1.1061,2.272-1.1062m0,1.7049c-0.37221,0.000016-0.65912,0.20975-0.86074,0.62919-0.20162,0.41947-0.30242,1.0148-0.30242,1.7861-0.000001,0.77804,0.1008,1.3802,0.30242,1.8064,0.20161,0.41947,0.48852,0.6292,0.86074,0.62919,0.37221,0.000012,0.65653-0.20972,0.85298-0.62919,0.20161-0.42622,0.30241-1.0283,0.30242-1.8064-0.000006-0.77126-0.10081-1.3666-0.30242-1.7861-0.20162-0.41945-0.48595-0.62918-0.85298-0.62919"/>
+	</g>
+	<path stroke-linejoin="miter" d="M5,21c8-16,26-15,39-15" stroke="#583e3e" stroke-linecap="round" stroke-miterlimit="4" stroke-dasharray="none" stroke-width="2.70000005" fill="none"/>
+	<path stroke-linejoin="miter" d="m2,3,0,21,44,0" stroke="#AAA" stroke-linecap="butt" stroke-width="1px" fill="none"/>
+</svg>

docs/extend-widgets/rst/OWAttributeSampler.py

 <icon>icons/AttributeSampler.png</icon>
 <priority>1020</priority>
 """
+import Orange
 
 from OWWidget import *
 import OWGUI
 
 class OWAttributeSampler(OWWidget):
     settingsList = []
-    contextHandlers = {"": DomainContextHandler("", [
-            ContextField("classAttribute", DomainContextHandler.Required),
-            ContextField("attributeList", DomainContextHandler.List + DomainContextHandler.SelectedRequired,
-                         selected="selectedAttributes")])}
+
+    # ~start context handler~
+    contextHandlers = {
+        "": DomainContextHandler(
+            "",
+            [ContextField("classAttribute", DomainContextHandler.Required),
+             ContextField("attributeList",
+                          DomainContextHandler.List +
+                          DomainContextHandler.SelectedRequired,
+                          selected="selectedAttributes")])}
+    # ~end context handler~
 
     def __init__(self, parent=None, signalManager=None):
         OWWidget.__init__(self, parent, signalManager, 'AttributeSampler')
 
-        self.inputs = [("Examples", ExampleTable, self.dataset)]
-        self.outputs = [("Examples", ExampleTable)]
+        self.inputs = [("Examples", Orange.data.Table, self.dataset)]
+        self.outputs = [("Examples", Orange.data.Table)]
 
         self.icons = self.createAttributeIconDict()
 
         self.classAttribute = None
         self.loadSettings()
 
-        OWGUI.listBox(self.controlArea, self, "selectedAttributes", "attributeList", box="Selected attributes", selectionMode = QListWidget.ExtendedSelection)
+        OWGUI.listBox(self.controlArea, self, "selectedAttributes",
+                      "attributeList",
+                      box="Selected attributes",
+                      selectionMode=QListWidget.ExtendedSelection)
+
         OWGUI.separator(self.controlArea)
-        self.classAttrCombo = OWGUI.comboBox(self.controlArea, self, "classAttribute", box="Class attribute")
+        self.classAttrCombo = OWGUI.comboBox(
+            self.controlArea, self, "classAttribute",
+            box="Class attribute")
+
         OWGUI.separator(self.controlArea)
-        OWGUI.button(self.controlArea, self, "Commit", callback = self.outputData)
+        OWGUI.button(self.controlArea, self, "Commit",
+                     callback=self.outputData)
 
         self.resize(150,400)
 
 
         self.classAttrCombo.clear()
         if data:
-            self.attributeList = [(attr.name, attr.varType) for attr in data.domain]
+            self.attributeList = [(attr.name, attr.varType)
+                                  for attr in data.domain]
             self.selectedAttributes = []
             for attrName, attrType in self.attributeList:
                 self.classAttrCombo.addItem(self.icons[attrType], attrName)
         if not self.data:
             self.send("Examples", None)
         else:
-            newDomain = orange.Domain([self.data.domain[i] for i in self.selectedAttributes], self.data.domain[self.classAttribute])
-            newData = orange.ExampleTable(newDomain, self.data)
+            newDomain = Orange.data.Domain(
+                [self.data.domain[i] for i in self.selectedAttributes],
+                self.data.domain[self.classAttribute])
+
+            newData = Orange.data.Table(newDomain, self.data)
             self.send("Examples", newData)
 
 
-##############################################################################
-# Test the widget, run from prompt
-
 if __name__=="__main__":
     appl = QApplication(sys.argv)
     ow = OWAttributeSampler()
     ow.show()
 
-    data = orange.ExampleTable('iris.tab')
+    data = Orange.data.Table('iris.tab')
     ow.dataset(data)
 
     appl.exec_()

docs/extend-widgets/rst/OWDataSamplerA.py

+"""
+<name>Data Sampler</name>
+<description>Randomly selects a subset of instances from the data set</description>
+<icon>icons/DataSamplerA.svg</icon>
+<priority>10</priority>
+"""
+
+import Orange
+from OWWidget import *
+import OWGUI
+
+class OWDataSamplerA(OWWidget):
+
+    def __init__(self, parent=None, signalManager=None):
+        OWWidget.__init__(self, parent, signalManager)
+
+        self.inputs = [("Data", Orange.data.Table, self.data)]
+        self.outputs = [("Sampled Data", Orange.data.Table)]
+
+        # GUI
+        box = OWGUI.widgetBox(self.controlArea, "Info")
+        self.infoa = OWGUI.widgetLabel(box, 'No data on input yet, waiting to get something.')
+        self.infob = OWGUI.widgetLabel(box, '')
+        self.resize(100,50)
+
+    def data(self, dataset):
+        if dataset:
+            self.infoa.setText('%d instances in input data set' % len(dataset))
+            indices = Orange.data.sample.SubsetIndices2(p0=0.1)
+            ind = indices(dataset)
+            sample = dataset.select(ind, 0)
+            self.infob.setText('%d sampled instances' % len(sample))
+            self.send("Sampled Data", sample)
+        else:
+            self.infoa.setText('No data on input yet, waiting to get something.')
+            self.infob.setText('')
+            self.send("Sampled Data", None)
+
+
+if __name__=="__main__":
+    appl = QApplication(sys.argv)
+    ow = OWDataSamplerA()
+    ow.show()
+    dataset = Orange.data.Table('iris.tab')
+    ow.data(dataset)
+    appl.exec_()
+

docs/extend-widgets/rst/OWDataSamplerB.py

 """
 <name>Data Sampler (B)</name>
 <description>Randomly selects a subset of instances from the data set</description>
-<icon>icons/DataSamplerB.png</icon>
+<icon>icons/DataSamplerB.svg</icon>
 <priority>20</priority>
 """
+import Orange
 from OWWidget import *
 import OWGUI
 
 class OWDataSamplerB(OWWidget):
     settingsList = ['proportion', 'commitOnChange']
     def __init__(self, parent=None, signalManager=None):
-        OWWidget.__init__(self, parent, signalManager, 'SampleDataB')
+        OWWidget.__init__(self, parent, signalManager)
 
-        self.inputs = [("Data", ExampleTable, self.data)]
-        self.outputs = [("Sampled Data", ExampleTable)]
+        self.inputs = [("Data", Orange.data.Table, self.data)]
+        self.outputs = [("Sampled Data", Orange.data.Table)]
 
         self.proportion = 50
         self.commitOnChange = 0
             self.infob.setText('')
 
     def selection(self):
-        indices = orange.MakeRandomIndices2(p0=self.proportion / 100.)
+        indices = Orange.data.sample.SubsetIndices2(p0=self.proportion / 100.)
         ind = indices(self.dataset)
         self.sample = self.dataset.select(ind, 0)
         self.infob.setText('%d sampled instances' % len(self.sample))
         if self.commitOnChange:
             self.commit()
 
-##############################################################################
-# Test the widget, run from prompt
 
 if __name__=="__main__":
     appl = QApplication(sys.argv)
     ow = OWDataSamplerB()
     ow.show()
-    dataset = orange.ExampleTable('iris.tab')
+    dataset = Orange.data.Table('iris.tab')
     ow.data(dataset)
     appl.exec_()

docs/extend-widgets/rst/OWDataSamplerC.py

 """
 <name>Data Sampler (C)</name>
 <description>Randomly selects a subset of instances from the data set</description>
-<icon>icons/DataSamplerC.png</icon>
+<icon>icons/DataSamplerC.svg</icon>
 <priority>30</priority>
 """
+import Orange
+
 from OWWidget import *
 import OWGUI
 
     def __init__(self, parent=None, signalManager=None):
         OWWidget.__init__(self, parent, signalManager, 'SampleDataC')
         
-        self.inputs = [("Data", ExampleTable, self.data)]
-        self.outputs = [("Sampled Data", ExampleTable), ("Other Data", ExampleTable)]
+        self.inputs = [("Data", Orange.data.Table, self.data)]
+        self.outputs = [("Sampled Data", Orange.data.Table),
+                        ("Other Data", Orange.data.Table)]
 
         self.proportion = 50
         self.commitOnChange = 0
             self.infob.setText('')
 
     def selection(self):
-        indices = orange.MakeRandomIndices2(p0=self.proportion / 100.)
+        indices = Orange.data.sample.SubsetIndices2(p0=self.proportion / 100.)
         ind = indices(self.dataset)
         self.sample = self.dataset.select(ind, 0)
         self.otherdata = self.dataset.select(ind, 1)
         if self.commitOnChange:
             self.commit()
 
-##############################################################################
-# Test the widget, run from prompt
 
 if __name__=="__main__":
     appl = QApplication(sys.argv)
     ow = OWDataSamplerC()
     ow.show()
-    dataset = orange.ExampleTable('iris.tab')
+    dataset = Orange.data.Table('iris.tab')
     ow.data(dataset)
     appl.exec_()

docs/extend-widgets/rst/OWLearningCurveA.py

 """
 <name>Learning Curve (A)</name>
 <description>Takes a data set and a set of learners and shows a learning curve in a table</description>
-<icon>icons/LearningCurveA.png</icon>
+<icon>icons/LearningCurve.svg</icon>
 <priority>1000</priority>
 """
 
+import Orange
+
 from OWWidget import *
-import OWGUI, orngTest, orngStat
+import OWGUI
 
 class OWLearningCurveA(OWWidget):
     settingsList = ["folds", "steps", "scoringF", "commitOnChange"]
-    
+
     def __init__(self, parent=None, signalManager=None):
         OWWidget.__init__(self, parent, signalManager, 'LearningCurveA')
 
-        self.inputs = [("Data", ExampleTable, self.dataset),
-                       ("Learner", orange.Learner, self.learner, Multiple)]
-        
+        self.inputs = [("Data", Orange.data.Table, self.dataset),
+                       ("Learner", Orange.core.Learner, self.learner,
+                        Multiple)]
+
         self.folds = 5     # cross validation folds
         self.steps = 10    # points in the learning curve
         self.scoringF = 0  # scoring function
         self.commitOnChange = 1 # compute curve on any change of parameters
         self.loadSettings()
-        self.setCurvePoints() # sets self.curvePoints, self.steps equidistantpoints from 1/self.steps to 1
-        self.scoring = [("Classification Accuracy", orngStat.CA), ("AUC", orngStat.AUC), ("BrierScore", orngStat.BrierScore), ("Information Score", orngStat.IS), ("Sensitivity", orngStat.sens), ("Specificity", orngStat.spec)]
+        self.setCurvePoints() # sets self.curvePoints, self.steps equidistant points from 1/self.steps to 1
+        self.scoring = [("Classification Accuracy", Orange.evaluation.scoring.CA),
+                        ("AUC", Orange.evaluation.scoring.AUC),
+                        ("BrierScore", Orange.evaluation.scoring.Brier_score),
+                        ("Information Score", Orange.evaluation.scoring.IS),
+                        ("Sensitivity", Orange.evaluation.scoring.Sensitivity),
+                        ("Specificity", Orange.evaluation.scoring.Specificity)]
         self.learners = [] # list of current learners from input channel, tuples (id, learner)
         self.data = None   # data on which to construct the learning curve
         self.curves = []   # list of evaluation results (one per learning curve point)
         self.infob = OWGUI.widgetLabel(box, 'No learners.')
 
         OWGUI.separator(self.controlArea)
+
         box = OWGUI.widgetBox(self.controlArea, "Evaluation Scores")
         scoringNames = [x[0] for x in self.scoring]
-        OWGUI.comboBox(box, self, "scoringF", items=scoringNames, callback=self.computeScores)
+        OWGUI.comboBox(box, self, "scoringF", items=scoringNames,
+                       callback=self.computeScores)
 
         OWGUI.separator(self.controlArea)
+
         box = OWGUI.widgetBox(self.controlArea, "Options")
-        OWGUI.spin(box, self, 'folds', 2, 100, step=1, label='Cross validation folds:  ',
+        OWGUI.spin(box, self, 'folds', 2, 100, step=1,
+                   label='Cross validation folds:  ',
                    callback=lambda: self.computeCurve(self.commitOnChange))
-        OWGUI.spin(box, self, 'steps', 2, 100, step=1, label='Learning curve points:  ',
-                   callback=[self.setCurvePoints, lambda: self.computeCurve(self.commitOnChange)])
+        OWGUI.spin(box, self, 'steps', 2, 100, step=1,
+                   label='Learning curve points:  ',
+                   callback=[self.setCurvePoints,
+                             lambda: self.computeCurve(self.commitOnChange)])
+        OWGUI.checkBox(box, self, 'commitOnChange', 'Apply setting on any change')
+        self.commitBtn = OWGUI.button(box, self, "Apply Setting",
+                                      callback=self.computeCurve, disabled=1)
 
-        OWGUI.checkBox(box, self, 'commitOnChange', 'Apply setting on any change')
-        self.commitBtn = OWGUI.button(box, self, "Apply Setting", callback=self.computeCurve, disabled=1)
+        OWGUI.rubber(self.controlArea)
 
         # table widget
-        self.table = OWGUI.table(self.mainArea, selectionMode=QTableWidget.NoSelection)
-                
+        self.table = OWGUI.table(self.mainArea,
+                                 selectionMode=QTableWidget.NoSelection)
+
         self.resize(500,200)
 
     ##############################################################################    
-    # slots: handle input signals        
+    # slots: handle input signals
 
     def dataset(self, data):
         if data:
             self.infoa.setText('No data on input.')
             self.curves = []
             self.scores = []
-        self.commitBtn.setEnabled(self.data<>None)
+        self.commitBtn.setEnabled(self.data is not None)
 
     def learner(self, learner, id=None):
         ids = [x[0] for x in self.learners]
         else:
             self.infob.setText("No learners.")
         self.commitBtn.setEnabled(len(self.learners))
-##        if len(self.scores):
+
         if self.data:
             self.setTable()
 
 
     def getLearningCurve(self, learners):   
         pb = OWGUI.ProgressBar(self, iterations=self.steps*self.folds)
-        curve = orngTest.learningCurveN(learners, self.data, folds=self.folds, proportions=self.curvePoints, callback=pb.advance)
+        curve = Orange.evaluation.testing.learning_curve_n(
+            learners, self.data, folds=self.folds,
+            proportions=self.curvePoints, callback=pb.advance)
         pb.finish()
         return curve
 
     def setCurvePoints(self):
-        self.curvePoints = [(x+1.)/self.steps for x in range(self.steps)]
+        self.curvePoints = [(x + 1.)/self.steps for x in range(self.steps)]
 
     def setTable(self):
         self.table.setColumnCount(0)
         for i in range(len(self.learners)):
             self.table.setColumnWidth(i, 80)
 
-##############################################################################
-# Test the widget, run from prompt
 
 if __name__=="__main__":
     appl = QApplication(sys.argv)
     ow = OWLearningCurveA()
     ow.show()
     
-    l1 = orange.BayesLearner()
+    l1 = Orange.classification.bayes.NaiveLearner()
     l1.name = 'Naive Bayes'
     ow.learner(l1, 1)
 
-    data = orange.ExampleTable('iris.tab')
+    data = Orange.data.Table('iris.tab')
     ow.dataset(data)
 
-    l2 = orange.BayesLearner()
+    l2 = Orange.classification.bayes.NaiveLearner()
     l2.name = 'Naive Bayes (m=10)'
-    l2.estimatorConstructor = orange.ProbabilityEstimatorConstructor_m(m=10)
-    l2.conditionalEstimatorConstructor = orange.ConditionalProbabilityEstimatorConstructor_ByRows(estimatorConstructor = orange.ProbabilityEstimatorConstructor_m(m=10))