source: orange/source/orange/lib_kernel.cpp @ 10220:b6e694facf69

Revision 10220:b6e694facf69, 207.5 KB checked in by Janez Demšar <janez.demsar@…>, 2 years ago (diff)

Reenabled renaming of Orange classes (ticket #1086), added a script for checking
that all classes are named so that unpickle can reconstruct them.

Line 
1/*
2    This file is part of Orange.
3
4    Copyright 1996-2010 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#ifdef _MSC_VER
22  #pragma warning (disable : 4786 4114 4018 4267 4244)
23#endif
24
25#include "vars.hpp"
26#include "domain.hpp"
27#include "examplegen.hpp"
28#include "table.hpp"
29#include "learn.hpp"
30#include "estimateprob.hpp"
31#include "preprocessors.hpp"
32#include "callback.hpp"
33
34#include "cls_value.hpp"
35#include "cls_example.hpp"
36#include "lib_kernel.hpp"
37#include "vectortemplates.hpp"
38
39
40#include "externs.px"
41
42#include "converts.hpp"
43#include "cls_orange.hpp"
44#include "slist.hpp"
45
46WRAPPER(ExampleTable);
47
48PStringList PStringList_FromArguments(PyObject *arg);
49
50/* This was moved from lib_vectors.cpp:
51    - nobody used it
52    - lib_vectors.cpp is automatically generated and I'd hate to add this as an exception
53
54int pt_FloatList(PyObject *args, void *floatlist)
55{
56  *(PFloatList *)(floatlist) = PFloatList_FromArguments(args);
57  return PyErr_Occurred() ? -1 : 0;
58}
59*/
60
61
62int pt_StringList(PyObject *args, void *stringList)
63{
64  PStringList &rsl = *(PStringList *)stringList;
65
66  if (PyOrStringList_Check(args))
67    rsl = PyOrange_AsStringList(args);
68  else
69    rsl = PStringList_FromArguments(args);
70
71  return rsl ? 1 : 0;
72}
73
74int ptn_StringList(PyObject *args, void *stringList)
75{
76  if (args == Py_None) {
77    *(PStringList *)stringList = PStringList();
78    return 1;
79  }
80
81  return pt_StringList(args, stringList);
82}
83
84
85/* ************ PROGRESS CALLBACK ************ */
86
87#include "progress.hpp"
88
89PyObject *ProgressCallback_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
90{ if (type == (PyTypeObject *)&PyOrProgressCallback_Type)
91    return setCallbackFunction(WrapNewOrange(mlnew TProgressCallback_Python(), type), args);
92  else
93    return WrapNewOrange(mlnew TProgressCallback_Python(), type);
94}
95
96
97PyObject *ProgressCallback__reduce__(PyObject *self)
98{
99  return callbackReduce(self, PyOrProgressCallback_Type);
100}
101
102
103PyObject *ProgressCallback_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(float[, Orange]) -> bool")
104{
105  PyTRY
106    NO_KEYWORDS
107
108    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrProgressCallback_Type) {
109      PyErr_Format(PyExc_SystemError, "ProgressCallback.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
110      return PYNULL;
111    }
112
113    float f;
114    POrange o;
115    if (!PyArg_ParseTuple(targs, "f|O&:ProgressCallback", &f, ccn_Orange, &o))
116      return PYNULL;
117
118    return PyInt_FromLong(SELF_AS(TProgressCallback)(f, o) ? 1 : 0);
119  PyCATCH
120}
121
122/* ************ VARIABLE ************ */
123
124PVarList PVarList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::P_FromArguments(arg); }
125PyObject *VarList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_FromArguments(type, arg); }
126PyObject *VarList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of Variable>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_new(type, arg, kwds); }
127PyObject *VarList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_getitem(self, index); }
128int       VarList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_setitem(self, index, item); }
129PyObject *VarList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_getslice(self, start, stop); }
130int       VarList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_setslice(self, start, stop, item); }
131Py_ssize_t       VarList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_len(self); }
132PyObject *VarList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_richcmp(self, object, op); }
133PyObject *VarList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_concat(self, obj); }
134PyObject *VarList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_repeat(self, times); }
135PyObject *VarList_str(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_str(self); }
136PyObject *VarList_repr(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_str(self); }
137int       VarList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_contains(self, obj); }
138PyObject *VarList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Variable) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_append(self, item); }
139PyObject *VarList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_extend(self, obj); }
140PyObject *VarList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> int") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_count(self, obj); }
141PyObject *VarList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> VarList") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_filter(self, args); }
142PyObject *VarList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> int") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_index(self, obj); }
143PyObject *VarList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_insert(self, args); }
144PyObject *VarList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_native(self); }
145PyObject *VarList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Variable") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_pop(self, args); }
146PyObject *VarList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_remove(self, obj); }
147PyObject *VarList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_reverse(self); }
148PyObject *VarList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_sort(self, args); }
149PyObject *VarList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_reduce(self); }
150
151
152PVarListList PVarListList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::P_FromArguments(arg); }
153PyObject *VarListList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_FromArguments(type, arg); }
154PyObject *VarListList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of VarList>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_new(type, arg, kwds); }
155PyObject *VarListList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_getitem(self, index); }
156int       VarListList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_setitem(self, index, item); }
157PyObject *VarListList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_getslice(self, start, stop); }
158int       VarListList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_setslice(self, start, stop, item); }
159Py_ssize_t       VarListList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_len(self); }
160PyObject *VarListList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_richcmp(self, object, op); }
161PyObject *VarListList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_concat(self, obj); }
162PyObject *VarListList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_repeat(self, times); }
163PyObject *VarListList_str(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_str(self); }
164PyObject *VarListList_repr(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_str(self); }
165int       VarListList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_contains(self, obj); }
166PyObject *VarListList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(VarList) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_append(self, item); }
167PyObject *VarListList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_extend(self, obj); }
168PyObject *VarListList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> int") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_count(self, obj); }
169PyObject *VarListList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> VarListList") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_filter(self, args); }
170PyObject *VarListList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> int") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_index(self, obj); }
171PyObject *VarListList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_insert(self, args); }
172PyObject *VarListList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_native(self); }
173PyObject *VarListList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> VarList") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_pop(self, args); }
174PyObject *VarListList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_remove(self, obj); }
175PyObject *VarListList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_reverse(self); }
176PyObject *VarListList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_sort(self, args); }
177PyObject *VarListList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_reduce(self); }
178
179
180PVarList knownVars(PyObject *keywords)
181{
182  PVarList variables;
183  PyObject *pyknownVars=keywords ? PyDict_GetItemString(keywords, "use") : PYNULL;
184  if (!pyknownVars || (pyknownVars == Py_None))
185    return PVarList();
186
187  if (PyOrVarList_Check(pyknownVars))
188    variables = ((GCPtr<TVarList>)(PyOrange_AS_Orange(pyknownVars)));
189
190  else if (PyOrDomain_Check(pyknownVars)) {
191    PDomain domain = PyOrange_AsDomain(pyknownVars);
192    variables = mlnew TVarList(domain->variables.getReference());
193    ITERATE(TMetaVector, mi, domain->metas)
194      variables->push_back((*mi).variable);
195  }
196
197  else
198    variables= PVarList_FromArguments(pyknownVars);
199
200  if (!variables)
201    raiseError("invalid value for 'use' argument"); // PYERROR won't do - NULL is a valid value to return...
202
203  return variables;
204}
205
206
207PDomain knownDomain(PyObject *keywords)
208{
209  PVarList variables;
210  PyObject *pyknownDomain = keywords ? PyDict_GetItemString(keywords, "domain") : PYNULL;
211  if (!pyknownDomain || (pyknownDomain == Py_None))
212    return PDomain();
213
214  if (!PyOrDomain_Check(pyknownDomain))
215    raiseError("invalid value for 'domain' argument"); // PYERROR won't do - NULL is a valid value to return...
216
217  return PyOrange_AsDomain(pyknownDomain);
218}
219
220
221TMetaVector *knownMetas(PyObject *keywords)
222{
223  if (!keywords)
224    return NULL;
225
226  PyObject *pyknownDomain = PyDict_GetItemString(keywords, "domain");
227  if (pyknownDomain && (pyknownDomain != Py_None)) {
228    if (!PyOrDomain_Check(pyknownDomain))
229      raiseError("invalid value for 'domain' argument"); // PYERROR won't do - NULL is a valid value to return...
230    return &PyOrange_AsDomain(pyknownDomain)->metas;
231  }
232
233  pyknownDomain = PyDict_GetItemString(keywords, "use");
234  if (pyknownDomain && PyOrDomain_Check(pyknownDomain))
235    return &PyOrange_AsDomain(pyknownDomain)->metas;
236
237  return NULL;
238}
239
240ABSTRACT(Variable - Orange.feature.Descriptor, Orange)
241C_NAMED(EnumVariable - Orange.feature.Discrete, Variable, "([name=, values=, autoValues=, distributed=, getValueFrom=])")
242C_NAMED(FloatVariable - Orange.feature.Continuous, Variable, "([name=, startValue=, endValue=, stepValue=, distributed=, getValueFrom=])")
243
244PyObject *PyVariable_MakeStatus_FromLong(long ok);
245
246/* Left for compatibility (also put into the header, as for others */
247PyObject *MakeStatus()
248{ PyObject *mt=PyModule_New("MakeStatus");
249  PyModule_AddObject(mt, "OK", PyVariable_MakeStatus_FromLong((long)TVariable::OK));
250  PyModule_AddObject(mt, "MissingValues", PyVariable_MakeStatus_FromLong((long)TVariable::MissingValues));
251  PyModule_AddObject(mt, "NoRecognizedValues", PyVariable_MakeStatus_FromLong((long)TVariable::NoRecognizedValues));
252  PyModule_AddObject(mt, "Incompatible", PyVariable_MakeStatus_FromLong((long)TVariable::Incompatible));
253  PyModule_AddObject(mt, "NotFound", PyVariable_MakeStatus_FromLong((long)TVariable::NotFound));
254  return mt;
255}
256
257PYCLASSCONSTANT(Variable, MakeStatus, MakeStatus())
258
259
260PyObject *Variable_getExisting(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, failOn]]) -> (Variable|None, status)")
261{
262  PyTRY
263    char *varName;
264    int varType;
265    PStringList values;
266    PStringList unorderedValues_asList;
267    int failOn = TVariable::Incompatible;
268
269    if (!PyArg_ParseTuple(args, "si|O&O&i:Variable.getExisting", &varName, &varType, ptn_StringList, &values, ptn_StringList, &unorderedValues_asList, &failOn))
270      return NULL;
271
272    set<string> unorderedValues;
273    if (unorderedValues_asList)
274      unorderedValues.insert(unorderedValues_asList->begin(), unorderedValues_asList->end());
275
276    int status;
277    PVariable var = TVariable::getExisting(varName, varType, values.getUnwrappedPtr(), &unorderedValues, failOn, &status);
278    return Py_BuildValue("NN", WrapOrange(var), PyVariable_MakeStatus_FromLong(status));
279  PyCATCH
280}
281
282
283PyObject *Variable_retrieve(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, failOn]]) -> (Variable|None, status)")
284{
285    return Variable_getExisting(NULL, args);
286}
287
288
289PyObject *newmetaid(PyObject *, PyObject *args);
290
291PyObject *Variable_new_meta_id(PyObject *, PyObject *args)  PYARGS(METH_VARARGS | METH_STATIC, "([Variable]) -> int")
292{
293    return newmetaid(NULL, args);
294}
295
296PyObject *Variable_make(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, createNewOn]]) -> (Variable|None, status)")
297{
298  PyTRY
299    char *varName;
300    int varType;
301    PStringList values;
302    PStringList unorderedValues_asList;
303    int createNewOn = TVariable::Incompatible;
304
305    if (!PyArg_ParseTuple(args, "si|O&O&i:Variable.make", &varName, &varType, ptn_StringList, &values, ptn_StringList, &unorderedValues_asList, &createNewOn))
306      return NULL;
307
308    set<string> unorderedValues;
309    if (unorderedValues_asList)
310      unorderedValues.insert(unorderedValues_asList->begin(), unorderedValues_asList->end());
311
312    int status;
313    PVariable var = TVariable::make(varName, varType, values.getUnwrappedPtr(), &unorderedValues, createNewOn, &status);
314    return Py_BuildValue("NN", WrapOrange(var), PyVariable_MakeStatus_FromLong(status));
315  PyCATCH
316}
317
318//set and get name
319int Variable_set_name(PyObject *self, PyObject *name)
320{ 
321    char *varName;
322    if (!PyString_Check(name))
323        PYERROR(PyExc_AttributeError, "string expected", 0);
324    varName = PyString_AsString(name);
325    PVariable var = PyOrange_AsVariable(self);
326    var->set_name(string(varName));
327    return 0;
328}
329
330
331PyObject *Variable_get_name(PyObject *self) 
332{
333    PVariable var = PyOrange_AsVariable(self);
334    return Py_BuildValue("s", var->get_name().c_str());
335}
336
337
338#include "stringvars.hpp"
339C_NAMED(StringVariable - Orange.feature.String, Variable, "([name=])")
340
341#include "pythonvars.hpp"
342C_NAMED(PythonVariable - Orange.feature.Python, Variable, "([name=])")
343
344PyObject *PythonValue_new(PyTypeObject *type, PyObject *args, PyObject *kwds) BASED_ON(SomeValue, "([object])")
345{
346  if (!PyTuple_Size(args))
347    return WrapNewOrange(mlnew TPythonValue(), type);
348
349  if (PyTuple_Size(args)==1)
350    return WrapNewOrange(mlnew TPythonValue(PyTuple_GET_ITEM(args, 0)), type);
351
352  else
353    PYERROR(PyExc_TypeError, "PythonValue.__init__ expects up to one Python object", PYNULL);
354}
355
356
357PyObject *PythonValueSpecial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) BASED_ON(Orange, "(int)") ALLOWS_EMPTY
358{
359  int vtype = 1;
360  if (!PyArg_ParseTuple(args, "|i:PythonValueSpecial.__init__", &vtype))
361    return PYNULL;
362
363  return WrapNewOrange(mlnew TPythonValueSpecial(vtype), type);
364}
365
366
367int PythonValue_set_value(PyObject *self, PyObject *value)
368{
369  Py_INCREF(value);
370  SELF_AS(TPythonValue).value = value;
371  return 0;
372}
373
374
375PyObject *PythonValue_get_value(PyObject *self)
376{
377  PyObject *res = SELF_AS(TPythonValue).value;
378  Py_INCREF(res);
379  return res;
380}
381
382
383PyObject *PythonValue__reduce__(PyObject *self)
384{
385  return Py_BuildValue("O(O)", (PyObject *)(self->ob_type), SELF_AS(TPythonValue).value);
386}
387
388
389PyObject *Variable_getattr(TPyOrange *self, PyObject *name)
390{
391  if (PyString_Check(name) && !strcmp(PyString_AsString(name), "attributes")
392      && (!self->orange_dict || !PyDict_Contains(self->orange_dict, name))) {
393    PyObject *dict = PyDict_New();
394    Orange_setattrDictionary(self, name, dict, false);
395    Py_DECREF(dict);
396  }
397
398  return Orange_getattr(self, name);
399}
400
401PyObject *Variable_randomvalue(PyObject *self, PyObject *args) PYARGS(0, "() -> Value")
402{ PyTRY
403    CAST_TO(TVariable, var);
404    if (args && !PyArg_ParseTuple(args, ""))
405      PYERROR(PyExc_TypeError, "no parameters expected", PYNULL);
406
407    return Value_FromVariableValue(PyOrange_AsVariable(self), var->randomValue());
408  PyCATCH
409}
410
411PyObject *Variable_firstvalue(PyObject *self, PyObject *args) PYARGS(0, "() -> Value | None")
412{ PyTRY
413    CAST_TO(TVariable, var);
414    if (args && !PyArg_ParseTuple(args, ""))
415      PYERROR(PyExc_TypeError, "no parameters expected", PYNULL);
416
417    TValue val;
418    if (!var->firstValue(val)) RETURN_NONE;
419
420    return Value_FromVariableValue(PyOrange_AsVariable(self), val);
421  PyCATCH
422}
423
424PyObject *Variable_nextvalue(PyObject *self, PyObject *val) PYARGS(METH_O, "(value)  -> Value | None")
425{ PyTRY
426    CAST_TO(TVariable, var);
427    if (   !PyOrValue_Check(val)
428        || (PyValue_AS_Variable(val) ? (PyValue_AS_Variable(val) != var) : (PyValue_AS_Value(val).varType != var->varType)))
429      PYERROR(PyExc_TypeError, "invalid value parameter", PYNULL);
430
431    TValue sval = PyValue_AS_Value(val);
432
433    if (!var->nextValue(sval))
434      RETURN_NONE;
435
436    return Value_FromVariableValue(PyOrange_AsVariable(self), sval);
437  PyCATCH
438}
439
440
441PyObject *Variable_computeValue(PyObject *self, PyObject *args) PYARGS(METH_O, "(example) -> Value")
442{ PyTRY
443    CAST_TO(TVariable, var);
444    if (!PyOrExample_Check(args))
445      PYERROR(PyExc_TypeError, "Variable.computeValue: 'Example' expected", PYNULL);
446
447    const TExample &ex = PyExample_AS_ExampleReference(args);
448
449    int idx = ex.domain->getVarNum(var, false);
450    if (idx != ILLEGAL_INT)
451      return Value_FromVariableValue(var, ex[idx]);
452
453    if (!var->getValueFrom)
454      PYERROR(PyExc_SystemError, "Variable.computeValue: 'getValueFrom' not defined", PYNULL);
455
456    return Value_FromVariableValue(var, var->computeValue(PyExample_AS_ExampleReference(args)));
457  PyCATCH
458}
459
460
461PyObject *Variable_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(value) -> Value")
462{ PyTRY
463    NO_KEYWORDS
464
465    PyObject *object;
466    TValue value;
467
468    if (   !PyArg_ParseTuple(args, "O:Variable.__call__", &object)
469        || !convertFromPython(object, value, PyOrange_AsVariable(self)))
470      return PYNULL;
471
472    return Value_FromVariableValue(PyOrange_AsVariable(self), value);
473  PyCATCH
474}
475
476
477PyObject *Variable_DC(PyObject *self) PYARGS(METH_NOARGS, "() -> DC")
478{
479  PyTRY
480    PVariable var = PyOrange_AsVariable(self);
481    return Value_FromVariableValue(var, var->DC());
482  PyCATCH
483}
484
485
486
487PyObject *Variable_DK(PyObject *self) PYARGS(METH_NOARGS, "() -> DK")
488{
489  PyTRY
490    PVariable var = PyOrange_AsVariable(self);
491    return Value_FromVariableValue(var, var->DK());
492  PyCATCH
493}
494
495
496PyObject *Variable_specialValue(PyObject *self, PyObject *arg) PYARGS(METH_O, "(int) -> special value")
497{
498  PyTRY
499    int valType;
500    if (!convertFromPython(arg, valType))
501      return PYNULL;
502    PVariable var = PyOrange_AsVariable(self);
503    return Value_FromVariableValue(var, var->specialValue(valType));
504  PyCATCH
505}
506
507
508
509PyObject *replaceVarWithEquivalent(PyObject *pyvar)
510{
511  PVariable newVar = PyOrange_AsVariable(pyvar);
512  TEnumVariable *enewVar = newVar.AS(TEnumVariable);
513  TVariable *oldVar = TVariable::getExisting(newVar->get_name(), newVar->varType, enewVar ? enewVar->values.getUnwrappedPtr() : NULL, NULL, TVariable::Incompatible);
514  if (oldVar && oldVar->isEquivalentTo(newVar.getReference())) {
515    if (newVar->sourceVariable)
516      oldVar->sourceVariable = newVar->sourceVariable;
517    if (newVar->getValueFrom)
518      oldVar->getValueFrom = newVar->getValueFrom;
519    Py_DECREF(pyvar);
520    return WrapOrange(PVariable(oldVar));
521  }
522  return pyvar;
523}
524
525
526PyObject *Variable__reduce__(PyObject *self)
527{
528    PyTRY
529        PyObject *name = PyObject_GetAttrString(self, "name");
530        PyObject *dict = packOrangeDictionary(self);
531        PyMapping_SetItemString(dict, "name", name);
532        Py_DECREF(name);
533        PyObject *state = PyDict_New();
534        PyObject *pygetvf = PyDict_GetItemString(dict, "get_value_from");
535        if (pygetvf) {
536            // get_value_from can contain a reference to this variable itself
537            PyDict_SetItemString(state, "get_value_from", pygetvf);
538            PyDict_DelItemString(dict, "get_value_from");
539        }
540        return Py_BuildValue("O(ON)N", getExportedFunction("__pickleLoaderVariable"), self->ob_type, dict, state); //packOrangeDictionary(self));
541    PyCATCH
542}
543
544
545PyObject *__pickleLoaderVariable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, dictionary)")
546{
547  PyTRY
548    PyTypeObject *type;
549    PyObject *dict;
550      if (!PyArg_ParseTuple(args, "OO:__pickleLoaderEnumVariable", &type, &dict))
551          return NULL;
552        PyObject *emptyTuple = PyTuple_New(0);
553        PyObject *pyVar = type->tp_new(type, emptyTuple, NULL);
554        Py_DECREF(emptyTuple);
555        if (unpackOrangeDictionary(pyVar, dict) == -1)
556          PYERROR(PyExc_AttributeError, "cannot construct the variable from the pickle", PYNULL)
557        return replaceVarWithEquivalent(pyVar);
558    PyCATCH
559}
560
561
562PyObject *EnumVariable__reduce__(PyObject *self)
563{
564    PyTRY
565        PyObject *name = PyObject_GetAttrString(self, "name");
566        PyObject *dict = packOrangeDictionary(self);
567        PyMapping_SetItemString(dict, "name", name);
568        Py_DECREF(name);
569        PyObject *state = PyDict_New();
570        PyObject *pygetvf = PyDict_GetItemString(dict, "get_value_from");
571        if (pygetvf) {
572            // get_value_from can contain a reference to this variable itself
573            PyDict_SetItemString(state, "get_value_from", pygetvf);
574            PyDict_DelItemString(dict, "get_value_from");
575        }
576        return Py_BuildValue("O(ON)N", getExportedFunction("__pickleLoaderEnumVariable"), self->ob_type, dict, state); //packOrangeDictionary(self));
577    PyCATCH
578}
579
580
581PyObject *__pickleLoaderEnumVariable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, dictionary)")
582{
583  PyTRY
584    PyTypeObject *type;
585    PyObject *dict;
586      if (!PyArg_ParseTuple(args, "OO:__pickleLoaderEnumVariable", &type, &dict))
587          return NULL;
588
589    char *name = NULL;
590    TStringList *values = NULL;
591
592    PyObject *pyname = PyDict_GetItemString(dict, "name");
593    if (pyname)
594      name = PyString_AsString(pyname);
595
596    PyObject *pyvalues = PyDict_GetItemString(dict, "values");
597    if (pyvalues)
598      values = PyOrange_AsStringList((TPyOrange *)pyvalues).getUnwrappedPtr();
599   
600    if (!(values && name))
601        PYERROR(PyExc_ValueError, "cannot construct the variable from the pickle", PYNULL);
602    TVariable *var = TVariable::getExisting(name, TValue::INTVAR, values, NULL);
603    PVariable pvar = var;
604    if (!var) {
605      TEnumVariable *evar = new TEnumVariable(name ? name : "");
606      pvar = evar;
607      if (values)
608        const_PITERATE(TStringList, vi, values)
609          evar->addValue(*vi);
610    }
611
612    PyObject *pyvar = WrapOrange(pvar);
613
614    PyObject *d_key, *d_value;
615    Py_ssize_t i = 0;
616    while (PyDict_Next(dict, &i, &d_key, &d_value)) {
617      if (   strcmp("values", PyString_AsString(d_key))
618          && Orange_setattrLow((TPyOrange *)pyvar, d_key, d_value, false) < 0
619         ) {
620          Py_DECREF(pyvar);
621          return NULL;
622        }
623    }
624
625    return replaceVarWithEquivalent(pyvar);
626    PyCATCH
627}
628
629PyObject *EnumVariable_getitem_sq(PyObject *self, Py_ssize_t index)
630{ PyTRY
631    CAST_TO(TEnumVariable, var)
632    if (!var->values || (index<0) || (index>=var->values->size()))
633      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
634    return Value_FromVariableValue(PyOrange_AsVariable(self), TValue((int)index));
635  PyCATCH
636}
637
638PyObject *EnumVariable_addValue(PyObject *self, PyObject *arg) PYARGS(METH_O, "(string) -> None")
639{
640  PyTRY
641    if (!PyString_Check(arg))
642      PYERROR(PyExc_TypeError, "string argument expected", PYNULL);
643    PyOrange_AsEnumVariable(self)->addValue(PyString_AsString(arg));
644    RETURN_NONE;
645  PyCATCH
646}
647
648PyObject *FloatVariable_getitem_sq(PyObject *self, Py_ssize_t index)
649{ PyTRY
650    CAST_TO(TFloatVariable, var);
651    if ((var->stepValue<=0) || (var->startValue>var->endValue))
652      PYERROR(PyExc_IndexError, "interval not specified", PYNULL);
653
654    float maxInd = (var->endValue - var->startValue)/var->stepValue;
655
656    if ((index<0) || (index>maxInd))
657      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
658    return Value_FromVariableValue(PyOrange_AsVariable(self), TValue(var->startValue+var->stepValue*index));
659  PyCATCH
660}
661
662
663bool convertFromPythonWithVariable(PyObject *obj, string &str)
664{ return convertFromPythonWithML(obj, str, *FindOrangeType(typeid(TVariable))); }
665
666
667bool varListFromDomain(PyObject *boundList, PDomain domain, TVarList &boundSet, bool allowSingle, bool checkForIncludance)
668{ if (PyOrVarList_Check(boundList)) {
669    PVarList variables = PyOrange_AsVarList(boundList);
670    if (checkForIncludance)
671      const_PITERATE(TVarList, vi, variables)
672        if (!domain || (domain->getVarNum(*vi, false)==ILLEGAL_INT)) {
673          PyErr_Format(PyExc_IndexError, "variable '%s' does not exist in the domain", (*vi)->get_name().c_str());
674          return false;
675        }
676    boundSet=variables.getReference();
677    return true;
678  }
679
680  if (PySequence_Check(boundList)) {
681    PyObject *iterator = PyObject_GetIter(boundList);
682    if (iterator) {
683      for(PyObject *item = PyIter_Next(iterator); item; item = PyIter_Next(iterator)) {
684        PVariable variable=varFromArg_byDomain(item, domain, checkForIncludance);
685        Py_DECREF(item);
686        if (!variable) {
687          Py_DECREF(iterator);
688          return false;
689        }
690        boundSet.push_back(variable);
691      }
692
693      Py_DECREF(iterator);
694      return true;
695    }
696  }
697
698  else if (allowSingle) {
699    PVariable variable=varFromArg_byDomain(boundList, domain, checkForIncludance);
700    if (variable) {
701      boundSet.push_back(variable);
702      return true;
703    }
704  }
705  PYERROR(PyExc_TypeError, "invalid argument (list of variables expected)", false);
706}
707
708
709// Given a parameter from Python and a domain, it returns a variable.
710// Python's parameter can be a string name, an index or Variable
711PVariable varFromArg_byDomain(PyObject *obj, PDomain domain, bool checkForIncludance)
712{ PVariable var;
713  if (domain) {
714    PyTRY
715      if (PyString_Check(obj)) {
716        const char *attr = PyString_AS_STRING(obj);
717        PVariable res = domain->getVar(attr, true, false);
718        if (!res)
719          PyErr_Format(PyExc_IndexError, "attribute '%s' not found", attr);
720        return res;
721      }
722      if (PyInt_Check(obj)) {
723        int idx = PyInt_AsLong(obj);
724
725        if (idx<0) {
726          PVariable res = domain->getMetaVar(idx, false);
727          if (!res)
728            PyErr_Format(PyExc_IndexError, "meta attribute %i not found", idx);
729          return res;
730        }
731
732        if (idx>=domain->variables->size())
733          PYERROR(PyExc_IndexError, "index out of range", PVariable());
734
735        return domain->getVar(idx);
736      }
737    PyCATCH_r(PVariable())
738  }
739
740  if (PyOrVariable_Check(obj)) {
741    PVariable var(PyOrange_AsVariable(obj));
742    if (checkForIncludance)
743      if (!domain || (domain->getVarNum(var, false)==ILLEGAL_INT))
744        PYERROR(PyExc_IndexError, "variable does not exist in the domain", PVariable());
745    return var;
746  }
747
748  PYERROR(PyExc_TypeError, "invalid type for variable", PVariable());
749}
750
751
752bool varListFromVarList(PyObject *boundList, PVarList varlist, TVarList &boundSet, bool allowSingle, bool checkForIncludance)
753{ if (PyOrVarList_Check(boundList)) {
754    PVarList variables = PyOrange_AsVarList(boundList);
755    if (checkForIncludance)
756      const_PITERATE(TVarList, vi, variables) {
757        TVarList::const_iterator fi(varlist->begin()), fe(varlist->end());
758        for(; (fi!=fe) && (*fi != *vi); fi++);
759        if (fi==fe) {
760          PyErr_Format(PyExc_IndexError, "variable '%s' does not exist in the domain", (*vi)->get_name().c_str());
761          return false;
762        }
763      }
764    boundSet = variables.getReference();
765    return true;
766  }
767
768  if (PyList_Check(boundList)) {
769    for(Py_ssize_t pos=0, max=PyList_Size(boundList); pos<max; pos++) {
770      PyObject *li=PyList_GetItem(boundList, pos);
771      if (!li)
772        PYERROR(PyExc_TypeError, "can't read the argument list", false);
773      PVariable variable = varFromArg_byVarList(li, varlist, checkForIncludance);
774      if (!variable)
775        return false;
776      boundSet.push_back(variable);
777    }
778    return true;
779  }
780  else if (allowSingle) {
781    PVariable variable = varFromArg_byVarList(boundList, varlist, checkForIncludance);
782    if (!variable)
783      return false;
784    boundSet.push_back(variable);
785    return true;
786  }
787
788  PYERROR(PyExc_TypeError, "invalid attribute for list of variables", false);
789}
790
791
792// Given a parameter from Python and a list of variables, it returns a variable.
793// Python's parameter can be a string name, an index or Variable
794PVariable varFromArg_byVarList(PyObject *obj, PVarList varlist, bool checkForIncludance)
795{ PVariable var;
796  if (varlist) {
797    PyTRY
798      if (PyString_Check(obj)) {
799        char *s = PyString_AS_STRING(obj);
800        TVarList::const_iterator fi(varlist->begin()), fe(varlist->end());
801        for(; (fi!=fe) && ((*fi)->get_name() != s); fi++);
802        if (fi==fe) {
803          PyErr_Format(PyExc_IndexError, "variable '%s' does not exist in the domain", s);
804          return PVariable();
805        }
806        else
807          return *fi;
808      }
809    PyCATCH_r(PVariable())
810  }
811
812  if (PyOrVariable_Check(obj)) {
813    PVariable var(PyOrange_AsVariable(obj));
814    if (checkForIncludance) {
815      TVarList::const_iterator fi(varlist->begin()), fe(varlist->end());
816      for(; (fi!=fe) && (*fi != var); fi++);
817      if (fi==fe)
818        PYERROR(PyExc_IndexError, "variable does not exist in the domain", PVariable());
819    }
820    return var;
821  }
822
823  PYERROR(PyExc_TypeError, "invalid type for variable", PVariable());
824}
825
826
827bool varNumFromVarDom(PyObject *pyvar, PDomain domain, int &attrNo)
828{
829  PVariable var=varFromArg_byDomain(pyvar, domain);
830  if (!var)
831    return false; // varFromArg_byDomain has already set the error message
832
833  PITERATE(TVarList, vi, domain->attributes)
834    if (*vi==var) {
835      attrNo = vi-domain->attributes->begin();
836      return true;
837    }
838
839  attrNo = domain->getMetaNum(var, false);
840  return attrNo != ILLEGAL_INT;
841}
842
843
844bool weightFromArg_byDomain(PyObject *pyweight, PDomain domain, int &weightID)
845{
846  if (!pyweight || (pyweight == Py_None))
847    weightID = 0;
848
849  else if (PyInt_Check(pyweight))
850    weightID =  PyInt_AsLong(pyweight);
851
852  else {
853    PVariable var = varFromArg_byDomain(pyweight, domain);
854    if (!var)
855      PYERROR(PyExc_TypeError, "invalid or unknown weight attribute", false);
856
857    weightID = domain->getVarNum(var);
858  }
859
860  return true;
861}
862
863
864static PExampleGenerator *ptw_examplegenerator;
865
866int ptw_weightByDomainCB(PyObject *args, void *weight)
867{
868  PDomain dom = ptw_examplegenerator ? (*ptw_examplegenerator)->domain : PDomain();
869  ptw_examplegenerator = NULL;
870  return weightFromArg_byDomain(args, dom, *(int *)weight) ? 1 : 0;
871}
872
873converter pt_weightByGen(PExampleGenerator &peg)
874{
875  ptw_examplegenerator = &peg;
876  return ptw_weightByDomainCB;
877}
878
879
880PyObject *StringValue_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(SomeValue - Orange.data.StringValue, "(string)")
881{ char *s;
882  if (!PyArg_ParseTuple(args, "s:StringValue", &s))
883    return PYNULL;
884
885  return WrapNewOrange(mlnew TStringValue(s), type);
886}
887
888
889PyObject *StringValue__reduce__(PyObject *self)
890{
891  return Py_BuildValue("O(s)", (PyObject *)(self->ob_type), SELF_AS(TStringValue).value.c_str());
892}
893
894
895/* ************ ATTRIBUTED FLOAT LIST ************ */
896
897PyObject *AttributedFloatList_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(FloatList, "(attributes, list)") ALLOWS_EMPTY
898{
899  PyObject *ob1 = NULL, *ob2 = NULL;
900  if (!PyArg_UnpackTuple(args, "AttributedFloatList.new", 0, 2, &ob1, &ob2))
901    return PYNULL;
902
903  PyObject *wabl = ListOfUnwrappedMethods<PAttributedFloatList, TAttributedFloatList, float>::_new(type, ob2 ? ob2 : ob1, keywds);
904
905  if (ob2) {
906    PVarList attributes = PVarList_FromArguments(ob1);
907    if (!attributes)
908      return PYNULL;
909
910    PyOrange_AsAttributedFloatList(wabl)->attributes = attributes;
911  }
912
913  return wabl;
914}
915
916
917PyObject * /*no pyxtract!*/ FloatList_getitem_sq(TPyOrange *self, Py_ssize_t index);
918int        /*no pyxtract!*/ FloatList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item);
919
920int AttributedList_getIndex(const int &listsize, PVarList attributes, PyObject *index)
921{
922  int res;
923
924  if (!listsize)
925    PYERROR(PyExc_IndexError, "the list is empty", ILLEGAL_INT);
926
927  if (PyInt_Check(index)) {
928    res = (int)PyInt_AsLong(index);
929    if (res < 0)
930      res += listsize;
931  }
932
933  else {
934    if (!attributes)
935      PYERROR(PyExc_AttributeError, "variable list not defined, need integer indices", ILLEGAL_INT);
936
937    if (PyOrVariable_Check(index)) {
938      PVariable var = PyOrange_AsVariable(index);
939      TVarList::const_iterator vi(attributes->begin()), ve(attributes->end());
940      int ind = 0;
941      for(; vi!=ve; vi++, ind++)
942        if (*vi == var) {
943          res = ind;
944          break;
945        }
946
947      if (vi == ve) {
948        PyErr_Format(PyExc_AttributeError, "attribute '%s' not found in the list", var->get_name().c_str());
949        return ILLEGAL_INT;
950      }
951    }
952
953    else if (PyString_Check(index)) {
954      const char *name = PyString_AsString(index);
955      TVarList::const_iterator vi(attributes->begin()), ve(attributes->end());
956      int ind = 0;
957      for(; vi!=ve; vi++, ind++)
958        if ((*vi)->get_name() == name) {
959          res = ind;
960          break;
961        }
962
963      if (vi == ve) {
964        PyErr_Format(PyExc_AttributeError, "attribute '%s' not found in the list", name);
965        return ILLEGAL_INT;
966      }
967    }
968
969    else {
970      PyErr_Format(PyExc_TypeError, "cannot index the list by '%s'", index->ob_type->tp_name);
971      return ILLEGAL_INT;
972    }
973  }
974
975  if ((res >= listsize) || (res < 0)) {
976    PyErr_Format(PyExc_IndexError, "index %i out of range 0-%i", res, listsize-1);
977    return ILLEGAL_INT;
978  }
979
980  return res;
981}
982
983
984PyObject *AttributedFloatList_getitem(TPyOrange *self, PyObject *index)
985{
986  PyTRY
987    CAST_TO(TAttributedFloatList, aflist)
988
989    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
990    if (ind == ILLEGAL_INT)
991      return PYNULL;
992
993    return FloatList_getitem_sq(self, ind);
994  PyCATCH
995}
996
997
998int AttributedFloatList_setitem(TPyOrange *self, PyObject *index, PyObject *value)
999{
1000  PyTRY
1001    CAST_TO_err(TAttributedFloatList, aflist, -1)
1002
1003    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
1004    if (ind == ILLEGAL_INT)
1005      return -1;
1006
1007    return FloatList_setitem_sq(self, ind, value);
1008  PyCATCH_1
1009}
1010
1011
1012
1013PyObject *AttributedBoolList_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(BoolList, "(attributes, list)") ALLOWS_EMPTY
1014{
1015  PyObject *ob1 = NULL, *ob2 = NULL;
1016  if (!PyArg_UnpackTuple(args, "AttributedBoolList.new", 0, 2, &ob1, &ob2))
1017    return PYNULL;
1018
1019  PyObject *wabl = ListOfUnwrappedMethods<PAttributedBoolList, TAttributedBoolList, bool>::_new(type, ob2 ? ob2 : ob1, keywds);
1020
1021  if (ob2) {
1022    PVarList attributes = PVarList_FromArguments(ob1);
1023    if (!attributes)
1024      return PYNULL;
1025
1026    PyOrange_AsAttributedBoolList(wabl)->attributes = attributes;
1027  }
1028
1029  return wabl;
1030}
1031
1032
1033PyObject * /*no pyxtract!*/ BoolList_getitem_sq(TPyOrange *self, Py_ssize_t index);
1034int        /*no pyxtract!*/ BoolList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item);
1035
1036
1037PyObject *AttributedBoolList_getitem(TPyOrange *self, PyObject *index)
1038{
1039  PyTRY
1040    CAST_TO(TAttributedBoolList, aflist)
1041
1042    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
1043    if (ind == ILLEGAL_INT)
1044      return PYNULL;
1045
1046    return BoolList_getitem_sq(self, ind);
1047  PyCATCH
1048}
1049
1050
1051int AttributedBoolList_setitem(TPyOrange *self, PyObject *index, PyObject *value)
1052{
1053  PyTRY
1054    CAST_TO_err(TAttributedBoolList, aflist, -1)
1055
1056    const int ind = AttributedList_getIndex(aflist->size(), aflist->attributes, index);
1057    if (ind == ILLEGAL_INT)
1058      return -1;
1059
1060    return BoolList_setitem_sq(self, ind, value);
1061  PyCATCH_1
1062}
1063
1064
1065/* ************ DOMAIN ************ */
1066
1067#include "domain.hpp"
1068
1069const TMetaDescriptor *metaDescriptorFromArg(TDomain &domain, PyObject *rar)
1070{
1071  TMetaDescriptor *desc = NULL;
1072
1073  if (PyString_Check(rar))
1074    desc = domain.metas[string(PyString_AsString(rar))];
1075
1076  else if (PyOrVariable_Check(rar))
1077    desc = domain.metas[PyOrange_AsVariable(rar)->get_name()];
1078
1079  else if (PyInt_Check(rar))
1080    desc = domain.metas[PyInt_AsLong(rar)];
1081
1082  else
1083    PYERROR(PyExc_TypeError, "invalid meta descriptor", NULL);
1084
1085  if (!desc)
1086    PYERROR(PyExc_AttributeError, "meta attribute does not exist", NULL);
1087
1088  return desc;
1089}
1090
1091
1092PyObject *Domain_isOptionalMeta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | int | descriptor) -> bool")
1093{
1094  PyTRY
1095    const TMetaDescriptor *desc = metaDescriptorFromArg(SELF_AS(TDomain), rar);
1096    return desc ? PyBool_FromLong(desc->optional ? 1 : 0) : NULL;
1097
1098  PyCATCH
1099}
1100
1101
1102PyObject *Domain_meta_id(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | descriptor) -> int")
1103{ PyTRY
1104    const TMetaDescriptor *desc = metaDescriptorFromArg(SELF_AS(TDomain), rar);
1105    return desc ? PyInt_FromLong(desc->id) : NULL;
1106  PyCATCH
1107}
1108
1109
1110PyObject *Domain_has_meta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | int | descriptor) -> bool")
1111{
1112  PyTRY
1113    CAST_TO(TDomain, domain)
1114
1115    TMetaDescriptor *desc = NULL;
1116
1117    if (PyString_Check(rar))
1118      desc = domain->metas[string(PyString_AsString(rar))];
1119
1120    else if (PyOrVariable_Check(rar))
1121      desc = domain->metas[PyOrange_AsVariable(rar)->get_name()];
1122
1123    else if (PyInt_Check(rar))
1124      desc = domain->metas[PyInt_AsLong(rar)];
1125
1126    else
1127      PYERROR(PyExc_TypeError, "invalid meta descriptor", NULL);
1128
1129    return PyBool_FromLong(desc ? 1 : 0);
1130  PyCATCH
1131}
1132
1133
1134PyObject *Domain_get_meta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "(name | int) -> Variable")
1135{ PyTRY
1136    const TMetaDescriptor *desc = metaDescriptorFromArg(SELF_AS(TDomain), rar);
1137    return desc ? WrapOrange(desc->variable) : NULL;
1138  PyCATCH
1139}
1140
1141
1142PyObject *Domain_getmetasLow(const TDomain &domain)
1143{
1144  PyObject *dict = PyDict_New();
1145  const_ITERATE(TMetaVector, mi, domain.metas)
1146    PyDict_SetItem(dict, PyInt_FromLong((*mi).id), WrapOrange((*mi).variable));
1147  return dict;
1148}
1149
1150
1151PyObject *Domain_getmetasLow(const TDomain &domain, const int optional)
1152{
1153  PyObject *dict = PyDict_New();
1154  const_ITERATE(TMetaVector, mi, domain.metas)
1155    if (optional == (*mi).optional)
1156      PyDict_SetItem(dict, PyInt_FromLong((*mi).id), WrapOrange((*mi).variable));
1157  return dict;
1158}
1159
1160
1161PyObject *Domain_get_metas(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([optional]) -> {int: Variable}")
1162{ PyTRY
1163    if (PyTuple_Size(args) && (PyTuple_GET_ITEM(args, 0) != Py_None)) {
1164      int opt;
1165      if (!PyArg_ParseTuple(args, "i:Domain.getmetas", &opt))
1166        return NULL;
1167
1168      return Domain_getmetasLow(SELF_AS(TDomain), opt);
1169    }
1170
1171    return Domain_getmetasLow(SELF_AS(TDomain));
1172  PyCATCH
1173}
1174
1175
1176PyObject *Domain_add_meta(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(id, descriptor[, optional]) -> None")
1177{ PyTRY
1178    CAST_TO(TDomain, domain);
1179
1180    int id;
1181    PVariable var;
1182    int opt = 0;
1183    if (!PyArg_ParseTuple(args, "iO&|i", &id, cc_Variable, &var, &opt))
1184      return PYNULL;
1185
1186    domain->metas.push_back(TMetaDescriptor(id, var, opt));
1187    domain->domainHasChanged();
1188    RETURN_NONE;
1189  PyCATCH
1190}
1191
1192
1193bool convertMetasFromPython(PyObject *dict, TMetaVector &metas)
1194{
1195  Py_ssize_t pos = 0;
1196  PyObject *pykey, *pyvalue;
1197  while (PyDict_Next(dict, &pos, &pykey, &pyvalue)) {
1198    if (!PyOrVariable_Check(pyvalue)) {
1199      PyErr_Format(PyExc_TypeError, "parsing meta attributes: dictionary value at position '%i' should be 'Variable', not '%s'", pos-1, pyvalue->ob_type->tp_name);
1200      return false;
1201    }
1202    if (!PyInt_Check(pykey) || (PyInt_AsLong(pykey)>=0))
1203      PYERROR(PyExc_TypeError, "parsing meta attributes: dictionary keys should be meta-ids (negative integers)", false);
1204
1205    metas.push_back(TMetaDescriptor((int)PyInt_AsLong(pykey), PyOrange_AsVariable(pyvalue)));
1206  }
1207
1208  return true;
1209}
1210
1211
1212PyObject *Domain_addmetasLow(TDomain &domain, PyObject *dict, const int opt = 0)
1213{
1214  TMetaVector metas;
1215  if (!convertMetasFromPython(dict, metas))
1216    return PYNULL;
1217
1218  ITERATE(TMetaVector, mi, metas) {
1219    (*mi).optional = opt;
1220    domain.metas.push_back(*mi);
1221  }
1222
1223  domain.domainHasChanged();
1224
1225  RETURN_NONE;
1226}
1227
1228
1229PyObject *Domain_add_metas(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "({id: descriptor, id: descriptor, ...}[, optional]) -> None")
1230{ PyTRY
1231    PyObject *pymetadict;
1232    int opt = 0;
1233    if (!PyArg_ParseTuple(args, "O|i", &pymetadict, &opt))
1234      PYERROR(PyExc_AttributeError, "Domain.addmetas expects a dictionary with id's and descriptors, optionally follow by an int flag 'optional'", PYNULL);
1235
1236    return Domain_addmetasLow(SELF_AS(TDomain), pymetadict, opt);
1237  PyCATCH
1238}
1239
1240
1241bool removeMeta(PyObject *rar, TMetaVector &metas)
1242{ TMetaVector::iterator mvi(metas.begin()), mve(metas.end());
1243
1244  if (PyInt_Check(rar)) {
1245    int id = PyInt_AsLong(rar);
1246    while((mvi!=mve) && ((*mvi).id!=id))
1247      mvi++;
1248  }
1249  else if (PyOrVariable_Check(rar))
1250    while((mvi!=mve) && ((*mvi).variable!=PyOrange_AsVariable(rar)))
1251      mvi++;
1252  else if (PyString_Check(rar)) {
1253    char *metaname = PyString_AsString(rar);
1254    while((mvi!=mve) && ((*mvi).variable->get_name()!=metaname))
1255      mvi++;
1256  }
1257  else
1258    mvi=mve;
1259
1260  if (mvi==mve)
1261    PYERROR(PyExc_AttributeError, "meta value not found", false);
1262
1263  metas.erase(mvi);
1264  return true;
1265}
1266
1267
1268PyObject *Domain_remove_meta(TPyOrange *self, PyObject *rar) PYARGS(METH_O, "({id0:desc0, id1:desc1, ...}) | ([id0|desc0, id1|desc1, ...]) -> None")
1269{ PyTRY
1270    CAST_TO(TDomain, domain);
1271
1272    if (PyDict_Check(rar)) {
1273      Py_ssize_t pos=0;
1274      PyObject *key, *value;
1275      TMetaVector newMetas=domain->metas;
1276      TMetaVector::iterator mve=domain->metas.end();
1277
1278      while (PyDict_Next(rar, &pos, &key, &value)) {
1279        if (!PyInt_Check(key) || !PyOrVariable_Check(value))
1280          PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
1281
1282        long idx=PyInt_AsLong(key);
1283        TMetaVector::iterator mvi(newMetas.begin());
1284        for(; (mvi!=mve) && ( ((*mvi).id!=idx) || (*mvi).variable!=PyOrange_AsVariable(value)); mvi++);
1285        if (mvi==mve)
1286          PYERROR(PyExc_AttributeError, "meta not found", PYNULL);
1287
1288        newMetas.erase(mvi);
1289      }
1290      domain->metas=newMetas;
1291      domain->domainHasChanged();
1292    }
1293
1294    else if (PyList_Check(rar)) {
1295      TMetaVector newMetas=domain->metas;
1296      for(Py_ssize_t pos=0, noel=PyList_Size(rar); pos!=noel; pos++)
1297        if (!removeMeta(PyList_GetItem(rar, pos), newMetas))
1298          return PYNULL;
1299      domain->metas=newMetas;
1300      domain->domainHasChanged();
1301    }
1302
1303    else if (!removeMeta(rar, domain->metas))
1304      return PYNULL;
1305
1306    RETURN_NONE;
1307  PyCATCH
1308}
1309
1310
1311PyObject *Domain_hasDiscreteAttributes(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(includeClass=0) -> int")
1312{
1313  PyTRY
1314      PyObject *includeClass = PYNULL;
1315      if (!PyArg_ParseTuple(args, "|O:Domain.hasDiscreteAttributes", &includeClass))
1316        return PYNULL;
1317
1318      return PyInt_FromLong(SELF_AS(TDomain).hasDiscreteAttributes(!includeClass || PyObject_IsTrue(includeClass)!=0) ? 1 : 0);
1319  PyCATCH
1320}
1321
1322
1323PyObject *Domain_hasContinuousAttributes(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(includeClass=0) -> int")
1324{
1325  PyTRY
1326      PyObject *includeClass = PYNULL;
1327      if (!PyArg_ParseTuple(args, "|O:Domain.hasContinuousAttributes", &includeClass))
1328        return PYNULL;
1329
1330      return PyInt_FromLong(SELF_AS(TDomain).hasContinuousAttributes(!includeClass || PyObject_IsTrue(includeClass)!=0) ? 1 : 0);
1331  PyCATCH
1332}
1333
1334
1335PyObject *Domain_hasOtherAttributes(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(includeClass=0) -> int")
1336{
1337  PyTRY
1338      PyObject *includeClass = PYNULL;
1339      if (!PyArg_ParseTuple(args, "|O:Domain.hasOtherAttributes", &includeClass))
1340        return PYNULL;
1341
1342      return PyInt_FromLong(SELF_AS(TDomain).hasOtherAttributes(!includeClass || PyObject_IsTrue(includeClass)!=0) ? 1 : 0);
1343  PyCATCH
1344}
1345
1346
1347Py_ssize_t Domain_len(TPyOrange *self)
1348{ PyTRY
1349    CAST_TO_err(TDomain, domain, -1);
1350    return domain->variables->size();
1351  PyCATCH_1
1352}
1353
1354
1355PyObject *Domain_index(PyObject *self, PyObject *arg) PYARGS(METH_O, "(variable) -> int")
1356{
1357  PyTRY
1358    CAST_TO(TDomain, domain);
1359
1360    PVariable variable = varFromArg_byDomain(arg, domain, true);
1361    return variable ? PyInt_FromLong(domain->getVarNum(variable)) : PYNULL;
1362  PyCATCH
1363}
1364
1365
1366int Domain_contains(PyObject *self, PyObject *arg)
1367{
1368  PyTRY
1369    CAST_TO_err(TDomain, domain, -1);
1370
1371    PVariable variable = varFromArg_byDomain(arg, domain, true);
1372    PyErr_Clear();
1373    return variable ? 1 : 0;
1374  PyCATCH_1
1375}
1376
1377CONSTRUCTOR_KEYWORDS(Domain, "source class_vars")
1378
1379PyObject *Domain_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange - Orange.data.Domain, "(list-of-attrs | domain [, hasClass | classVar | None] [,domain | list-of-attrs | source=domain])")
1380{ PyTRY
1381    PyObject *list;
1382    PyObject *arg1 = PYNULL;
1383    PyObject *arg2 = PYNULL;
1384    PyObject *pyclassvars = PYNULL;
1385
1386    if (PyArg_ParseTuple(args, "O|OO", &list, &arg1, &arg2)) {
1387
1388      if (keywds) {
1389          PyObject *key, *value;
1390          Py_ssize_t pos = 0;
1391          while (PyDict_Next(keywds, &pos, &key, &value)) {
1392              if (!PyString_Check(key)) {
1393                  Py_XDECREF(pyclassvars);
1394                  PYERROR(PyExc_TypeError, "keyword argument name must be a string", PYNULL);
1395              }
1396              if (!strcmp(PyString_AS_STRING(key), "source")) {
1397                  if (arg1 && arg2) {
1398                      Py_XDECREF(pyclassvars);
1399                      PYERROR(PyExc_TypeError, "Domain: too many arguments", PYNULL);
1400                  }
1401                  Py_INCREF(value);
1402                  if (!arg1) {
1403                      arg1 = value;
1404                  }
1405                  else {
1406                      arg2 = value;
1407                  }
1408              }
1409              else if (!strcmp(PyString_AS_STRING(key), "class_vars")) {
1410                  Py_INCREF(value);
1411                  pyclassvars = value;
1412              }
1413              else {
1414                  Py_XDECREF(pyclassvars);
1415                  PyErr_Format(PyExc_ValueError, "unexpected keyword argument '%s'", PyString_AS_STRING(key));
1416                  return PYNULL;
1417              }
1418          }
1419      }
1420
1421      if (PyOrDomain_Check(list)) {
1422
1423        PDomain dom = PyOrange_AsDomain(list);
1424        TDomain *newdomain = NULL;
1425
1426        if (arg1) {
1427          if (PyString_Check(arg1) || PyOrVariable_Check(arg1)) {
1428            PVariable classVar = varFromArg_byDomain(arg1, dom, false);
1429            if (!classVar) {
1430                Py_XDECREF(pyclassvars);
1431                return PYNULL;
1432            }
1433            TVarList attributes = dom->variables.getReference();
1434            int vnumint = dom->getVarNum(classVar, false);
1435            if (vnumint>=0) {
1436                attributes.erase(attributes.begin()+vnumint);
1437            }
1438            newdomain = mlnew TDomain(classVar, attributes);
1439          }
1440          else if (PyInt_Check(arg1) || (arg1==Py_None)) {
1441            TVarList attributes = dom->variables.getReference();
1442            if (PyObject_IsTrue(arg1))
1443                newdomain = CLONE(TDomain, dom), type;
1444            else
1445                newdomain = mlnew TDomain(PVariable(), dom->variables.getReference());
1446          }
1447          else {
1448              Py_XDECREF(pyclassvars);
1449              PYERROR(PyExc_TypeError, "Domain: invalid arguments for constructor (I'm unable to guess what you meant)", PYNULL);
1450          }
1451        }
1452        else {
1453           newdomain = CLONE(TDomain, dom);
1454        }
1455        if (pyclassvars) {
1456            if (!varListFromVarList(pyclassvars, dom->variables, newdomain->classVars.getReference(), false, false)) {
1457                Py_DECREF(pyclassvars);
1458                mldelete newdomain;
1459                return PYNULL;
1460            }
1461            Py_DECREF(pyclassvars);
1462        }
1463        return WrapNewOrange(newdomain, type);
1464      }
1465
1466      /* Now, arg1 can be either
1467           - NULL
1468           - source (i.e. Domain or list of variables)
1469           - boolean that tells whether we have a class
1470           - class variable
1471         If arg1 is present but is not source, arg2 can be source
1472      */
1473
1474      PVarList source;
1475      PVariable classVar;
1476      bool hasClass = true;
1477
1478      if (arg1) {
1479        if (PyOrDomain_Check(arg1))
1480          source = PyOrange_AsDomain(arg1)->variables;
1481        else if (PyOrVarList_Check(arg1))
1482          source = PyOrange_AsVarList(arg1);
1483        else if (PyList_Check(arg1))
1484          source = PVarList_FromArguments(arg1);
1485        else if (PyOrVariable_Check(arg1))
1486          classVar = PyOrange_AsVariable(arg1);
1487        else
1488          hasClass = (PyObject_IsTrue(arg1) != 0);
1489      }
1490      if (arg2) {
1491        if (source) {
1492          PYERROR(PyExc_TypeError, "Domain: invalid argument 3", PYNULL);
1493        }
1494        else
1495          if (PyOrDomain_Check(arg2)) {
1496            PDomain sourceDomain = PyOrange_AsDomain(arg2);
1497            source = mlnew TVarList(sourceDomain->variables.getReference());
1498            ITERATE(TMetaVector, mi, sourceDomain->metas)
1499              source->push_back((*mi).variable);
1500          }
1501
1502          else if (PyOrVarList_Check(arg2))
1503            source = PyOrange_AsVarList(arg2);
1504          else if (PyList_Check(arg2))
1505            source = PVarList_FromArguments(arg2);
1506      }
1507
1508      TVarList variables;
1509      if (!varListFromVarList(list, source, variables, true, false))
1510        return PYNULL;
1511
1512      if (hasClass && !classVar && variables.size()) {
1513        classVar = variables.back();
1514        variables.erase(variables.end()-1);
1515      }
1516
1517      TDomain *newdomain = mlnew TDomain(classVar, variables);
1518      if (pyclassvars) {
1519          if (!varListFromVarList(pyclassvars, source, newdomain->classVars.getReference(), false, false)) {
1520              Py_DECREF(pyclassvars);
1521              mldelete newdomain;
1522              return PYNULL;
1523          }
1524          Py_DECREF(pyclassvars);
1525      }
1526      return WrapNewOrange(newdomain, type);
1527    }
1528
1529    PYERROR(PyExc_TypeError, "invalid parameters (list of 'Variable' expected)", PYNULL);
1530
1531  PyCATCH
1532}
1533
1534
1535PyObject *Domain__reduce__(PyObject *self)
1536{
1537  CAST_TO(TDomain, domain)
1538
1539
1540  return Py_BuildValue("O(ONNNNN)N", getExportedFunction("__pickleLoaderDomain"),
1541                                   self->ob_type,
1542                                   WrapOrange(domain->attributes),
1543                                   WrapOrange(domain->classVar),
1544                                   WrapOrange(domain->classVars),
1545                                   Domain_getmetasLow(SELF_AS(TDomain), false),
1546                                   Domain_getmetasLow(SELF_AS(TDomain), true),
1547                                   packOrangeDictionary(self));
1548}
1549
1550PyObject *__pickleLoaderDomain(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, attributes, classVar, classVars, req_metas, opt_metas)")
1551{
1552  PyTRY {
1553    if (!args || !PyTuple_Check(args))
1554        PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL)
1555
1556    int arg_size = PyTuple_Size(args);
1557
1558    if (!(arg_size == 6 || arg_size == 5))
1559        PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL);
1560
1561    PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
1562    PyObject *attributes = PyTuple_GET_ITEM(args, 1);
1563    PyObject *classVar = PyTuple_GET_ITEM(args, 2);
1564
1565    PyObject *classVars = NULL;
1566    PyObject *req_metas = NULL;
1567    PyObject *opt_metas = NULL;
1568
1569    if (arg_size == 5)
1570    {
1571        // Old tuple format (pre multiclass support)
1572        req_metas = PyTuple_GET_ITEM(args, 3);
1573        opt_metas = PyTuple_GET_ITEM(args, 4);
1574
1575    }
1576    else
1577    {
1578        classVars = PyTuple_GET_ITEM(args, 3);
1579        req_metas = PyTuple_GET_ITEM(args, 4);
1580        opt_metas = PyTuple_GET_ITEM(args, 5);
1581    }
1582
1583    if (!PyOrVarList_Check(attributes) || (classVars && !PyOrVarList_Check(classVars)) || !PyDict_Check(req_metas) || !PyDict_Check(opt_metas))
1584      PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL);
1585
1586
1587    TDomain *domain = NULL;
1588    if (classVar == Py_None)
1589      domain = new TDomain(PVariable(), PyOrange_AsVarList(attributes).getReference());
1590    else if (PyOrVariable_Check(classVar))
1591      domain = new TDomain(PyOrange_AsVariable(classVar), PyOrange_AsVarList(attributes).getReference());
1592    else
1593      PYERROR(PyExc_TypeError, "invalid arguments for the domain unpickler", NULL);
1594
1595    if (classVars != NULL)
1596        domain->classVars = PyOrange_AsVarList(classVars);
1597    else
1598        domain->classVars = PVarList(new TVarList());
1599
1600
1601    PyObject *pydomain = WrapNewOrange(domain, type);
1602
1603    PyObject *res;
1604    res = Domain_addmetasLow(*domain, req_metas, false);
1605    if (!res) {
1606      Py_DECREF(pydomain);
1607      return NULL;
1608    }
1609    Py_DECREF(res);
1610
1611    res = Domain_addmetasLow(*domain, opt_metas, true);
1612    if (!res) {
1613      Py_DECREF(pydomain);
1614      return NULL;
1615    }
1616    Py_DECREF(res);
1617
1618    return pydomain;
1619  }
1620  PyCATCH
1621}
1622
1623
1624PyObject *Domain_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(example) -> Example")
1625{ PyTRY
1626    NO_KEYWORDS
1627
1628    TExample *ex;
1629    if (!PyArg_ParseTuple(args, "O&", ptr_Example, &ex))
1630      PYERROR(PyExc_TypeError, "invalid parameters (Example expected)", PYNULL);
1631
1632    return Example_FromWrappedExample(PExample(mlnew TExample(PyOrange_AsDomain(self), *ex)));
1633  PyCATCH
1634}
1635
1636
1637PyObject *Domain_getitem(TPyOrange *self, PyObject *index)
1638{ PyTRY
1639    PVariable var = varFromArg_byDomain(index, PyOrange_AsDomain(self), true);
1640    return var ? WrapOrange(var) : PYNULL;
1641  PyCATCH
1642}
1643
1644
1645PyObject *Domain_getitem_sq(TPyOrange *self, Py_ssize_t index)
1646{ PyTRY
1647    CAST_TO(TDomain, domain)
1648    if ((index<0) || (index>=domain->variables->size()))
1649      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
1650    return WrapOrange(domain->getVar(index));
1651  PyCATCH
1652}
1653
1654
1655PyObject *Domain_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop)
1656{
1657  PyTRY
1658    CAST_TO(TDomain, domain);
1659
1660    int ds=domain->variables->size();
1661    if (start>ds)
1662      start=ds;
1663    else if (start<0)
1664      start=0;
1665
1666    if (stop>ds) stop=ds;
1667    else if (stop<0) stop=0;
1668    stop-=start;
1669    PyObject *list=PyList_New(stop);
1670    if (!list)
1671      return NULL;
1672    TVarList::iterator vi(domain->variables->begin()+start);
1673    for(Py_ssize_t i=0; i<stop; i++)
1674      PyList_SetItem(list, i, WrapOrange(*(vi++)));
1675    return list;
1676  PyCATCH
1677}
1678
1679
1680const string &nonamevar = string("<noname>");
1681
1682inline const string &namefrom(const string &name)
1683{ return name.length() ? name : nonamevar; }
1684
1685string TDomain2string(TPyOrange *self)
1686{ CAST_TO_err(TDomain, domain, "<invalid domain>")
1687
1688  string res;
1689
1690  int added=0;
1691  PITERATE(TVarList, vi, domain->variables)
1692    res+=(added++ ? ", " : "[") + namefrom((*vi)->get_name());
1693
1694  if (added) {
1695    res+="]";
1696    if (domain->metas.size())
1697      res+=", {";
1698  }
1699  else
1700    if (domain->metas.size())
1701      res+="{";
1702
1703  added=0;
1704  ITERATE(TMetaVector, mi, domain->metas) {
1705    char pls[256];
1706    sprintf(pls, "%s%i:%s", (added++) ? ", " : "", int((*mi).id), namefrom((*mi).variable->get_name()).c_str());
1707    res+=pls;
1708  }
1709  if (added)
1710    res+="}";
1711
1712  return res;
1713}
1714
1715
1716
1717PyObject *Domain_repr(TPyOrange *pex)
1718{ PyTRY
1719    PyObject *result = callbackOutput((PyObject *)pex, NULL, NULL, "repr", "str");
1720    if (result)
1721      return result;
1722
1723    return PyString_FromString(TDomain2string(pex).c_str());
1724  PyCATCH
1725}
1726
1727
1728PyObject *Domain_str(TPyOrange *pex)
1729{ PyTRY
1730    PyObject *result = callbackOutput((PyObject *)pex, NULL, NULL, "str", "repr");
1731    if (result)
1732      return result;
1733
1734    return PyString_FromString(TDomain2string(pex).c_str());
1735  PyCATCH
1736}
1737
1738
1739int Domain_set_classVar(PyObject *self, PyObject *arg) PYDOC("Domain's class attribute")
1740{
1741  PyTRY
1742    CAST_TO_err(TDomain, domain, -1);
1743
1744    if (arg==Py_None)
1745      domain->removeClass();
1746    else
1747      if (PyOrVariable_Check(arg))
1748        domain->changeClass(PyOrange_AsVariable(arg));
1749      else PYERROR(PyExc_AttributeError, "invalid type for class", -1)
1750
1751    return 0;
1752  PyCATCH_1
1753}
1754
1755PyObject *Domain_checksum(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
1756{ return PyInt_FromLong(SELF_AS(TDomain).sumValues()); }
1757
1758
1759/* ************ RANDOM GENERATORS ************** */
1760
1761#include "random.hpp"
1762
1763C_UNNAMED(RandomGenerator, Orange, "() -> 32-bit random int")
1764
1765PyObject *RandomGenerator_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange, "([int])")
1766{ PyTRY
1767      int i = 0;
1768      if (!PyArg_ParseTuple(args, "|i:RandomGenerator.__new__", &i))
1769        return PYNULL;
1770
1771      return WrapNewOrange(mlnew TRandomGenerator(i), type);
1772  PyCATCH
1773}
1774
1775
1776PyObject *RandomGenerator__reduce__(PyObject *self)
1777{
1778  cMersenneTwister &mt = SELF_AS(TRandomGenerator).mt;
1779
1780  return Py_BuildValue("O(Os#ii)N", getExportedFunction("__pickleLoaderRandomGenerator"),
1781                                    self->ob_type,
1782                                    (char *)(mt.state), (mt.next-mt.state + mt.left + 1) * sizeof(long),
1783                                    mt.next - mt.state,
1784                                    mt.left,
1785                                    packOrangeDictionary(self));
1786}
1787
1788
1789PyObject *__pickleLoaderRandomGenerator(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, state, next_offset, left)")
1790{
1791  PyTypeObject *type;
1792  int offs;
1793  int left;
1794  char *buff;
1795  int bufsize;
1796  if (!PyArg_ParseTuple(args, "Os#ii", &type, &buff, &bufsize, &offs, &left))
1797    return PYNULL;
1798
1799  TRandomGenerator *rg = new TRandomGenerator;
1800
1801  cMersenneTwister &mt = rg->mt;
1802  memcpy(mt.state, buff, bufsize);
1803  mt.next = mt.state + offs;
1804  mt.left = left;
1805
1806  return WrapNewOrange(rg, type);
1807}
1808
1809
1810PyObject *RandomGenerator_reset(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "([new_seed]) -> None")
1811{ PyTRY
1812    int seed = numeric_limits<int>::min();
1813    if (!PyArg_ParseTuple(args, "|i:RandomGenerator.reset", &seed))
1814      return PYNULL;
1815
1816    if (seed != numeric_limits<int>::min())
1817      SELF_AS(TRandomGenerator).initseed = seed;
1818
1819    SELF_AS(TRandomGenerator).reset();
1820    RETURN_NONE;
1821  PyCATCH
1822}
1823
1824PyObject *RandomGenerator_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("() -> 32-bit random int")
1825{ PyTRY
1826    NO_KEYWORDS
1827
1828    if (args) {
1829      if (PyTuple_Size(args) == 1) {
1830        return PyInt_FromLong((long)SELF_AS(TRandomGenerator).randlong(PyInt_AsLong(PyTuple_GET_ITEM(args, 0))));
1831      }
1832      PYERROR(PyExc_TypeError, "zero or one argument expected", PYNULL);
1833    }
1834
1835    return PyInt_FromLong((long)SELF_AS(TRandomGenerator)());
1836  PyCATCH
1837}
1838
1839
1840PyObject *stdRandomGenerator()
1841{ return WrapOrange(globalRandom); }
1842
1843PYCONSTANTFUNC(globalRandom, stdRandomGenerator)
1844
1845
1846/* ************ EXAMPLE GENERATOR ************ */
1847
1848TFiletypeDefinition::TFiletypeDefinition(const char *an, PyObject *al, PyObject *as)
1849: name(an),
1850  loader(al),
1851  saver(as)
1852{
1853  if (loader == Py_None)
1854    loader = PYNULL;
1855  else
1856    Py_INCREF(loader);
1857
1858  if (saver == Py_None)
1859    saver = PYNULL;
1860  else
1861    Py_INCREF(saver);
1862}
1863
1864
1865TFiletypeDefinition::TFiletypeDefinition(const TFiletypeDefinition &other)
1866: name(other.name),
1867  extensions(other.extensions),
1868  loader(other.loader),
1869  saver(other.saver)
1870{
1871  Py_XINCREF(loader);
1872  Py_XINCREF(saver);
1873}
1874
1875
1876TFiletypeDefinition::~TFiletypeDefinition()
1877{
1878  Py_XDECREF(loader);
1879  Py_XDECREF(saver);
1880}
1881
1882
1883vector<TFiletypeDefinition> filetypeDefinitions;
1884
1885/* lower case to avoid any ambiguity problems (don't know how various compilers can react when
1886   registerFiletype is cast by the code produced by pyxtract */
1887ORANGE_API void registerFiletype(const char *name, const vector<string> &extensions, PyObject *loader, PyObject *saver)
1888{
1889  TFiletypeDefinition ftd(name, loader, saver);
1890  ftd.extensions = extensions;
1891  filetypeDefinitions.push_back(ftd);
1892}
1893
1894bool fileExists(const string &s);
1895const char *getExtension(const char *name);
1896
1897
1898vector<TFiletypeDefinition>::iterator findFiletypeByExtension(const char *name, bool needLoader, bool needSaver, bool exhaustive)
1899{
1900  const char *extension = getExtension(name);
1901
1902  if (extension) {
1903    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1904      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1905        ITERATE(TStringList, ei, (*fi).extensions)
1906          if (*ei == extension)
1907            return fi;
1908  }
1909
1910  else if (exhaustive) {
1911    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1912      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1913        ITERATE(TStringList, ei, (*fi).extensions)
1914          if (fileExists(name + *ei))
1915            return fi;
1916  }
1917
1918  return filetypeDefinitions.end();
1919}
1920
1921
1922PyObject *registerFileType(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(name, extensions, loader, saver) -> None")
1923{
1924  char *name;
1925  PyObject *pyextensions, *loader, *saver;
1926  if (!PyArg_ParseTuple(args, "sOOO:registerFiletype", &name, &loader, &saver, &pyextensions))
1927    return PYNULL;
1928
1929  TFiletypeDefinition ftd(name, loader, saver);
1930
1931  if (PyString_Check(pyextensions))
1932    ftd.extensions.push_back(PyString_AsString(pyextensions));
1933  else {
1934    PStringList extensions = PStringList_FromArguments(pyextensions);
1935    if (!extensions)
1936      return PYNULL;
1937    ftd.extensions = extensions.getReference();
1938  }
1939
1940  vector<TFiletypeDefinition>::iterator fi(filetypeDefinitions.begin()), fe(filetypeDefinitions.begin());
1941  for(; (fi != fe) && ((*fi).name != name); fi++);
1942
1943  if (fi==fe)
1944    filetypeDefinitions.push_back(ftd);
1945  else
1946    *fi = ftd;
1947
1948  RETURN_NONE;
1949}
1950
1951
1952extern char *fileTypes[][2];
1953
1954PyObject *getRegisteredFileTypes(PyObject *, PyObject *, PyObject *) PYARGS(METH_NOARGS, "() -> ((extension, description, loader, saver), ...)")
1955{
1956  char *(*t)[2] = fileTypes;
1957  while(**t)
1958    t++;
1959
1960  int builtIns = t-fileTypes;
1961  int i = 0;
1962  PyObject *types = PyTuple_New(builtIns + filetypeDefinitions.size());
1963  for(t = fileTypes; **t; t++)
1964    PyTuple_SetItem(types, i++, Py_BuildValue("ss", (*t)[0], (*t)[1]));
1965
1966  ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions) {
1967    string exts;
1968    ITERATE(TStringList, ei, (*fi).extensions)
1969      exts += (exts.size() ? " *" : "*") + *ei;
1970
1971    PyObject *ploader = (*fi).loader, *psaver = (*fi).saver;
1972    if (!ploader) {
1973      ploader = Py_None;
1974      Py_INCREF(Py_None);
1975    }
1976    if (!psaver) {
1977      psaver = Py_None;
1978      Py_INCREF(Py_None);
1979    }
1980    PyTuple_SetItem(types, i++, Py_BuildValue("ssOO", (*fi).name.c_str(), exts.c_str(), ploader, psaver));
1981  }
1982
1983  return types;
1984}
1985
1986#include "examplegen.hpp"
1987#include "table.hpp"
1988#include "filter.hpp"
1989
1990
1991PyObject *loadDataByPython(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool exhaustiveFilesearch, bool &fileFound)
1992{
1993  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, true, false, exhaustiveFilesearch);
1994  fileFound = fi!=filetypeDefinitions.end();
1995
1996  if (!fileFound)
1997    return PYNULL;
1998
1999  PyObject *res = PyObject_Call((*fi).loader, argstuple, keywords);
2000  if (!res)
2001    throw pyexception();
2002  if (res == Py_None)
2003    return res;
2004
2005  bool gotTuple = PyTuple_Check(res);
2006  PyObject *res1 = gotTuple ? PyTuple_GET_ITEM(res, 0) : res;
2007
2008  if (PyOrExampleTable_Check(res1))
2009    return res;
2010
2011  PExampleGenerator gen;
2012  if (!exampleGenFromParsedArgs(res1, gen)) {
2013    Py_DECREF(res);
2014    return PYNULL;
2015  }
2016
2017  TExampleTable *table = gen.AS(TExampleTable);
2018  if (!table) {
2019    Py_DECREF(res);
2020    return PYNULL;
2021  }
2022
2023  if (gotTuple) {
2024    PyObject *nres = PyTuple_New(PyTuple_Size(res));
2025    PyTuple_SetItem(nres, 0, WrapNewOrange(table, type));
2026    for(Py_ssize_t i = 1; i < PyTuple_Size(res); i++)
2027      PyTuple_SetItem(nres, i, PyTuple_GET_ITEM(res, i));
2028
2029    Py_DECREF(res);
2030    return nres;
2031  }
2032  else {
2033    Py_DECREF(res);
2034    return WrapNewOrange(table, type);
2035  }
2036}
2037
2038bool readUndefinedSpecs(PyObject *keyws, char *&DK, char *&DC);
2039
2040
2041bool readBoolFlag(PyObject *keywords, char *flag)
2042{
2043  PyObject *pyflag = keywords ? PyDict_GetItemString(keywords, flag) : PYNULL;
2044  return pyflag && PyObject_IsTrue(pyflag);
2045}
2046
2047bool hasFlag(PyObject *keywords, char *flag)
2048{
2049  return keywords && (PyDict_GetItemString(keywords, flag) != PYNULL);
2050}
2051
2052
2053TExampleTable         *readTable(char *filename, const int createNewOn, vector<int> &status, vector<pair<int, int> > &metaStatus, const char *DK, const char *DC, bool noExcOnUnknown = false, bool noCodedDiscrete = false, bool noClass = false);
2054TExampleGenerator *readGenerator(char *filename, const int createNewOn, vector<int> &status, vector<pair<int, int> > &metaStatus, const char *DK, const char *DC, bool noExcOnUnknown = false, bool noCodedDiscrete = false, bool noClass = false);
2055
2056PyObject *encodeStatus(const vector<int> &status);
2057PyObject *encodeStatus(const vector<pair<int, int> > &metaStatus);
2058
2059char *obsoleteFlags[] = {"dontCheckStored", "dontStore", "use", "useMetas", "domain", 0 };
2060
2061
2062PyObject *loadDataFromFileNoSearch(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2063{
2064  PyObject *res;
2065
2066  bool pythonFileFound;
2067  res = loadDataByPython(type, filename, argstuple, keywords, false, pythonFileFound);
2068  if (res) {
2069    if (res != Py_None) {
2070      if (!PyTuple_Check(res))
2071        return res;
2072
2073      PyObject *pygen = PyTuple_GetItem(res, 0);
2074      Py_INCREF(pygen);
2075
2076      if (PyTuple_Size(res) >= 2) {
2077        Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", PyTuple_GET_ITEM(res, 1), false);
2078        Orange_setattrDictionary((TPyOrange *)pygen, "attribute_load_status", PyTuple_GET_ITEM(res, 1), false);
2079      }
2080      if (PyTuple_Size(res) >= 3) {
2081        Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", PyTuple_GET_ITEM(res, 2), false);
2082        Orange_setattrDictionary((TPyOrange *)pygen, "meta_attribute_load_status", PyTuple_GET_ITEM(res, 2), false);
2083      }
2084      return pygen;
2085    }
2086
2087    else
2088      Py_DECREF(Py_None);
2089  }
2090
2091  PyErr_Clear();
2092
2093  for(char * const *of = obsoleteFlags; *of; of++)
2094    if (hasFlag(keywords, *of))
2095      raiseWarning("flag '%s' is not supported any longer", *of);
2096
2097  int createNewOn = TVariable::Incompatible;
2098  if (hasFlag(keywords, "createNewOn"))
2099    convertFromPython(PyDict_GetItemString(keywords, "createNewOn"), createNewOn);
2100
2101  char *DK = NULL, *DC = NULL;
2102  if (!readUndefinedSpecs(keywords, DK, DC))
2103    return PYNULL;
2104
2105  char *errs = NULL;
2106  vector<int> status;
2107  vector<pair<int, int> > metaStatus;
2108  try {
2109    TExampleGenerator *generator =
2110      generatorOnly ? readGenerator(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"))
2111                    : readTable(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"));
2112    if (generator) {
2113      PyObject *pygen = WrapNewOrange(generator, type);
2114      PyObject *pystatus = encodeStatus(status);
2115      PyObject *pymetastatus = encodeStatus(metaStatus);
2116      Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", pystatus, false);
2117      Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", pymetastatus, false);
2118      Py_DECREF(pystatus);
2119      Py_DECREF(pymetastatus);
2120      return pygen;
2121    }
2122  }
2123  catch (mlexception err) {
2124    errs = strdup(err.what());
2125  }
2126
2127  res = loadDataByPython(type, filename, argstuple, keywords, true, pythonFileFound);
2128  if (res)
2129    return res;
2130
2131  if (pythonFileFound) {
2132    PYERROR(PyExc_SystemError, "cannot load the file", PYNULL);
2133  }
2134  else {
2135    PyErr_SetString(PyExc_SystemError, errs);
2136    free(errs);
2137    return PYNULL;
2138  }
2139}
2140
2141PyObject *loadDataFromFilePath(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly, const char *path)
2142{
2143  if (!path) {
2144    return NULL;
2145  }
2146
2147  #if defined _WIN32
2148  const char sep = ';';
2149  const char pathsep = '\\';
2150  #else
2151  const char sep = ':';
2152  const char pathsep = '/';
2153  #endif
2154  const int flen = strlen(filename);
2155
2156  for(const char *pi = path, *pe=pi; *pi; pi = pe+1) {
2157    for(pe = pi; *pe && *pe != sep; pe++);
2158    const int plen = pe-pi;
2159     char *npath = strncpy(new char[plen+flen+2], pi, pe-pi);
2160    if (!plen || (pe[plen] != pathsep)) {
2161      npath[plen] = pathsep;
2162      strcpy(npath+plen+1, filename);
2163    }
2164    else {
2165      strcpy(npath+plen, filename);
2166    }
2167    PyObject *res = loadDataFromFileNoSearch(type, npath, argstuple, keywords, generatorOnly);
2168    PyErr_Clear();
2169    if (res) {
2170      return res;
2171    }
2172    if (!*pe)
2173      break;
2174  }
2175
2176  return NULL;
2177}
2178
2179PyObject *loadDataFromFile(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2180{
2181  PyObject *ptype, *pvalue, *ptraceback;
2182  PyObject *res;
2183
2184  res = loadDataFromFileNoSearch(type, filename, argstuple, keywords, generatorOnly);
2185  if (res) {
2186    return res;
2187  }
2188
2189  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
2190
2191  // Try to find the file in the doc/datasets directory
2192  PyObject *configurationModule = PyImport_ImportModule("orngConfiguration");
2193  if (configurationModule) {
2194    PyObject *datasetsPath = PyDict_GetItemString(PyModule_GetDict(configurationModule), "datasetsPath");
2195    if (datasetsPath)
2196      res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, PyString_AsString(datasetsPath));
2197    Py_DECREF(configurationModule);
2198  }
2199  else {
2200    PyErr_Clear();
2201  }
2202
2203  if (!res) {
2204      // Try fo find the file using Orange.data.io.find_file
2205      PyObject *ioModule = PyImport_ImportModule("Orange.data.io");
2206      if (ioModule) {
2207          PyObject *find_file = PyObject_GetAttrString(ioModule, "find_file");
2208          if (find_file){
2209              PyObject *py_args = Py_BuildValue("(s)", filename);
2210              PyObject *ex_filename = PyObject_Call(find_file, py_args, NULL);
2211              if (ex_filename && PyString_Check(ex_filename)){
2212                  res = loadDataFromFileNoSearch(type, PyString_AsString(ex_filename), argstuple, keywords, generatorOnly);
2213                  Py_DECREF(ex_filename);
2214              }
2215              PyErr_Clear();
2216              Py_DECREF(py_args);
2217              Py_DECREF(find_file);
2218          }
2219          Py_DECREF(ioModule);
2220      }
2221  }
2222  if (!res)
2223      PyErr_Clear();
2224
2225  if (!res) {
2226    res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, getenv("ORANGE_DATA_PATH"));
2227  }
2228
2229  if (res) {
2230    Py_XDECREF(ptype);
2231    Py_XDECREF(pvalue);
2232    Py_XDECREF(ptraceback);
2233    return res;
2234  }
2235
2236  PyErr_Restore(ptype, pvalue, ptraceback);
2237  return PYNULL;
2238}
2239
2240
2241int pt_ExampleGenerator(PyObject *args, void *egen)
2242{
2243  *(PExampleGenerator *)(egen) = PyOrExampleGenerator_Check(args) ? PyOrange_AsExampleGenerator(args)
2244                                                                  : PExampleGenerator(readListOfExamples(args));
2245
2246  if (!*(PExampleGenerator *)(egen))
2247    PYERROR(PyExc_TypeError, "invalid example generator", 0)
2248  else
2249    return 1;
2250}
2251
2252
2253static PDomain ptd_domain;
2254
2255int ptdf_ExampleGenerator(PyObject *args, void *egen)
2256{
2257  egen = NULL;
2258
2259  try {
2260    if (PyOrExampleGenerator_Check(args)) {
2261      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
2262      if (gen->domain == ptd_domain)
2263        *(PExampleGenerator *)(egen) = gen;
2264      else
2265        *(PExampleGenerator *)(egen) = mlnew TExampleTable(ptd_domain, gen);
2266    }
2267    else
2268      *(PExampleGenerator *)(egen) = PExampleGenerator(readListOfExamples(args, ptd_domain));
2269
2270    ptd_domain = PDomain();
2271
2272    if (!*(PExampleGenerator *)(egen))
2273      PYERROR(PyExc_TypeError, "invalid example generator", 0)
2274    else
2275      return 1;
2276  }
2277
2278  catch (...) {
2279    ptd_domain = PDomain();
2280    throw;
2281  }
2282}
2283
2284
2285converter ptd_ExampleGenerator(PDomain domain)
2286{
2287  ptd_domain = domain;
2288  return ptdf_ExampleGenerator;
2289}
2290
2291
2292CONSTRUCTOR_KEYWORDS(ExampleGenerator, "domain use useMetas dontCheckStored dontStore filterMetas DC DK NA noClass noCodedDiscrete")
2293
2294// Class ExampleGenerator is abstract in C++; this constructor returns the derived classes
2295
2296NO_PICKLE(ExampleGenerator)
2297
2298PyObject *ExampleGenerator_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(Orange, "(filename)")
2299{
2300  PyTRY
2301    char *filename = NULL;
2302    if (PyArg_ParseTuple(argstuple, "s", &filename))
2303      return loadDataFromFile(type, filename, argstuple, keywords, true);
2304    else
2305      return PYNULL;
2306  PyCATCH;
2307}
2308
2309
2310PExampleGenerator exampleGenFromParsedArgs(PyObject *args)
2311{
2312 if (PyOrOrange_Check(args)) {
2313   if (PyOrExampleGenerator_Check(args))
2314      return PyOrange_AsExampleGenerator(args);
2315    else
2316      PYERROR(PyExc_TypeError, "example generator expected", NULL);
2317  }
2318  return PExampleGenerator(readListOfExamples(args));
2319}
2320
2321
2322PExampleGenerator exampleGenFromArgs(PyObject *args, int &weightID)
2323{
2324  PyObject *examples, *pyweight = NULL;
2325  if (!PyArg_UnpackTuple(args, "exampleGenFromArgs", 1, 2, &examples, &pyweight))
2326    return PExampleGenerator();
2327
2328  PExampleGenerator egen = exampleGenFromParsedArgs(examples);
2329  if (!egen || !weightFromArg_byDomain(pyweight, egen->domain, weightID))
2330    return PExampleGenerator();
2331
2332  return egen;
2333}
2334
2335
2336PExampleGenerator exampleGenFromArgs(PyObject *args)
2337{
2338  if (PyTuple_GET_SIZE(args) != 1)
2339    PYERROR(PyExc_TypeError, "exampleGenFromArgs: examples expected", PExampleGenerator())
2340
2341  return exampleGenFromParsedArgs(PyTuple_GET_ITEM(args, 0));
2342}
2343
2344
2345PyObject *ExampleGenerator_native(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
2346{ PyTRY
2347    bool tuples = false;
2348    PyObject *forDC = NULL;
2349    PyObject *forDK = NULL;
2350    PyObject *forSpecial = NULL;
2351    if (keyws) {
2352      PyObject *pytuples = PyDict_GetItemString(keyws, "tuple");
2353      tuples = pytuples && (PyObject_IsTrue(pytuples) != 0);
2354
2355      forDC = PyDict_GetItemString(keyws, "substitute_DC");
2356      if (!forDC) {
2357          forDC = PyDict_GetItemString(keyws, "substituteDC");
2358      }
2359      forDC = PyDict_GetItemString(keyws, "substitute_DK");
2360      if (!forDC) {
2361          forDC = PyDict_GetItemString(keyws, "substituteDK");
2362      }
2363      forDC = PyDict_GetItemString(keyws, "substitute_other");
2364      if (!forDC) {
2365          forDC = PyDict_GetItemString(keyws, "substituteOther");
2366      }
2367    }
2368
2369    int natvt=2;
2370    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=2)))
2371      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2372    CAST_TO(TExampleGenerator, eg);
2373
2374    PyObject *list=PyList_New(0);
2375    EITERATE(ei, *eg)
2376      if (natvt<=1) {
2377        PyObject *obj=convertToPythonNative(*ei, natvt, tuples, forDK, forDC, forSpecial);
2378        PyList_Append(list, obj);
2379        Py_DECREF(obj);
2380      }
2381        // What happens with: convertToPythonNative((*ei, natvt, tuples))? Funny.
2382      else {
2383        PyObject *example=Example_FromExampleCopyRef(*ei);
2384        if (!example) {
2385          PyMem_DEL(list);
2386          PYERROR(PyExc_SystemError, "out of memory", PYNULL);
2387        }
2388        PyList_Append(list, example);
2389        Py_DECREF(example);
2390      }
2391
2392    return list;
2393  PyCATCH
2394}
2395
2396
2397PVariableFilterMap PVariableFilterMap_FromArguments(PyObject *arg);
2398
2399int VariableFilterMap_setitemlow(TVariableFilterMap *aMap, PVariable var, PyObject *pyvalue);
2400
2401inline PVariableFilterMap sameValuesMap(PyObject *dict, PDomain dom)
2402{ TVariableFilterMap *vfm = mlnew TVariableFilterMap;
2403  PVariableFilterMap wvfm = vfm;
2404
2405  Py_ssize_t pos=0;
2406  PyObject *pykey, *pyvalue;
2407  while (PyDict_Next(dict, &pos, &pykey, &pyvalue)) {
2408    PVariable var = varFromArg_byDomain(pykey, dom, true);
2409    if (!var || (VariableFilterMap_setitemlow(vfm, var, pyvalue) < 0))
2410      return PVariableFilterMap();
2411  }
2412
2413  return wvfm;
2414}
2415
2416inline PPreprocessor pp_sameValues(PyObject *dict, PDomain dom)
2417{ PVariableFilterMap vfm = sameValuesMap(dict, dom);
2418  return vfm ? mlnew TPreprocessor_take(vfm) : PPreprocessor();
2419}
2420
2421inline PFilter filter_sameValues(PyObject *dict, PDomain domain, PyObject *kwds = PYNULL)
2422{ PVariableFilterMap svm = sameValuesMap(dict, domain);
2423  if (!svm)
2424    return PFilter();
2425
2426  PyObject *pyneg = kwds ? PyDict_GetItemString(kwds, "negate") : NULL;
2427  return TPreprocessor_take::constructFilter(svm, domain, true, pyneg && PyObject_IsTrue(pyneg));
2428}
2429
2430PyObject *applyPreprocessor(PPreprocessor preprocessor, PExampleGenerator gen, bool weightGiven, int weightID)
2431{ if (!preprocessor)
2432    return PYNULL;
2433
2434  int newWeight;
2435  PExampleGenerator newGen = preprocessor->call(gen, weightID, newWeight);
2436  return weightGiven ? Py_BuildValue("Ni", WrapOrange(newGen), newWeight) : WrapOrange(newGen);
2437}
2438
2439
2440
2441PyObject *applyFilter(PFilter filter, PExampleGenerator gen, bool weightGiven, int weightID);
2442
2443PyObject *ExampleGenerator_select(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
2444/* This function is a spaghetti for compatibility reasons. Most of its functionality
2445   has been moved to specialized functions (changeDomain, filter). The only two
2446   functions that 'select' should be used for is selection of examples by vector
2447   of bools or indices (LongList) */
2448{
2449  PyTRY
2450    CAST_TO(TExampleGenerator, eg);
2451    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2452
2453    /* ***** SELECTION BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
2454    /* Deprecated: use method 'filter' instead */
2455    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2456      return applyPreprocessor(pp_sameValues(keywords, eg->domain), weg, false, 0);
2457    }
2458
2459
2460    PyObject *mplier;
2461    PyObject *pyweight = NULL;
2462    if (PyArg_ParseTuple(args, "O|O", &mplier, &pyweight)) {
2463      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
2464      bool negate = pyneg && PyObject_IsTrue(pyneg);
2465      bool secondArgGiven = (pyweight != NULL);
2466
2467      /* ***** SELECTION BY VECTOR OF BOOLS ****** */
2468      if (PyList_Check(mplier) && PyList_Size(mplier) && PyInt_Check(PyList_GetItem(mplier, 0))) {
2469        Py_ssize_t nole = PyList_Size(mplier);
2470
2471        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2472        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2473        Py_ssize_t i = 0;
2474
2475        if (secondArgGiven) {
2476          if (PyInt_Check(pyweight)) {
2477            int compVal = (int)PyInt_AsLong(pyweight);
2478            TExampleIterator ei = eg->begin();
2479            for(; ei && (i<nole); ++ei) {
2480              PyObject *lel = PyList_GetItem(mplier, i++);
2481              if (!PyInt_Check(lel))
2482                break;
2483
2484              if (negate != (PyInt_AsLong(lel)==compVal))
2485                newTable->addExample(*ei);
2486            }
2487
2488            if ((i==nole) && !ei)
2489              return WrapOrange(newGen);
2490          }
2491        }
2492        else {
2493          TExampleIterator ei = eg->begin();
2494          for(; ei && (i<nole); ++ei) {
2495            PyObject *lel = PyList_GetItem(mplier, i++);
2496            if (negate != (PyObject_IsTrue(lel) != 0))
2497              newTable->addExample(*ei);
2498          }
2499
2500          if ((i==nole) && !ei)
2501            return WrapOrange(newGen);
2502        }
2503      }
2504
2505      PyErr_Clear();
2506
2507
2508      /* ***** SELECTION BY LONGLIST ****** */
2509      if (PyOrLongList_Check(mplier)) {
2510        PLongList llist = PyOrange_AsLongList(mplier);
2511        TLongList::iterator lli(llist->begin()), lle(llist->end());
2512
2513        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2514        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2515
2516        TExampleIterator ei = eg->begin();
2517
2518        if (secondArgGiven) {
2519          if (!PyInt_Check(pyweight))
2520            PYERROR(PyExc_AttributeError, "example selector must be an integer", PYNULL);
2521
2522          int compVal = (int)PyInt_AsLong(pyweight);
2523          for(; ei && (lli!=lle); ++ei, lli++)
2524            if (negate != (*lli==compVal))
2525              newTable->addExample(*ei);
2526        }
2527        else {
2528          for(; ei && (lli != lle); ++ei, lli++)
2529            if (negate != (*lli != 0))
2530              newTable->addExample(*ei);
2531        }
2532
2533        if ((lli==lle) && !ei)
2534          return WrapOrange(newGen);
2535
2536        PYERROR(PyExc_IndexError, "ExampleGenerator.select: invalid list size", PYNULL)
2537      }
2538
2539      PyErr_Clear();
2540
2541      /* ***** CHANGING DOMAIN ***** */
2542      /* Deprecated: use method 'translate' instead. */
2543      if (PyOrDomain_Check(mplier)) {
2544        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(PyOrange_AsDomain(mplier), weg)));
2545        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2546      }
2547
2548
2549      /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2550      /* Deprecated: use method 'translate' instead. */
2551      TVarList attributes;
2552      if (varListFromDomain(mplier, eg->domain, attributes, true, false)) {
2553        PDomain newDomain;
2554        TVarList::iterator vi, ve;
2555        for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2556        if (vi==ve)
2557          newDomain = mlnew TDomain(PVariable(), attributes);
2558        else {
2559          attributes.erase(vi);
2560          newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2561        }
2562
2563        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2564        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2565      }
2566
2567      PyErr_Clear();
2568
2569
2570      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
2571      /* Deprecated: use method 'filter' instead. */
2572      if (PyDict_Check(mplier)) {
2573        int weightID;
2574        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2575          return applyFilter(filter_sameValues(mplier, eg->domain), weg, secondArgGiven, weightID);
2576      }
2577
2578
2579      /* ***** PREPROCESSING ***** */
2580      /* Deprecated: call preprocessor instead. */
2581      if (PyOrPreprocessor_Check(mplier)) {
2582        int weightID;
2583        if (weightFromArg_byDomain(pyweight, eg->domain, weightID)) {
2584
2585          PExampleGenerator res;
2586          int newWeight;
2587          PyTRY
2588            NAME_CAST_TO(TPreprocessor, mplier, pp);
2589            if (!pp)
2590              PYERROR(PyExc_TypeError, "invalid object type (preprocessor announced, but not passed)", PYNULL)
2591            res = (*pp)(weg, weightID, newWeight);
2592          PyCATCH
2593
2594          return secondArgGiven ? Py_BuildValue("Ni", WrapOrange(res), newWeight) : WrapOrange(res);
2595        }
2596      }
2597
2598      /* ***** APPLY FILTER ***** */
2599      /* Deprecated: use method 'filter' instead. */
2600      if (PyOrFilter_Check(mplier)) {
2601        int weightID;
2602        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2603          return applyFilter(PyOrange_AsFilter(mplier), weg, secondArgGiven, weightID);
2604      }
2605    }
2606    PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2607  PyCATCH
2608}
2609
2610
2611PyObject *ExampleGenerator_filter(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
2612{
2613  PyTRY
2614    CAST_TO(TExampleGenerator, eg);
2615    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2616
2617    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2618      return applyFilter(filter_sameValues(keywords, eg->domain, keywords), weg, false, 0);
2619    }
2620
2621    if (PyTuple_Size(args)==1) {
2622      PyObject *arg = PyTuple_GET_ITEM(args, 0);
2623
2624      if (PyDict_Check(arg))
2625        return applyFilter(filter_sameValues(arg, eg->domain, keywords), weg, false, 0);
2626
2627      if (PyOrFilter_Check(arg))
2628          return applyFilter(PyOrange_AsFilter(arg), weg, false, 0);
2629    }
2630
2631    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter expects a list of conditions or orange.Filter", PYNULL)
2632  PyCATCH
2633}
2634
2635
2636PyObject *ExampleGenerator_translate(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "translate(domain | list-of-attributes) -> ExampleTable")
2637{
2638  PyTRY
2639    CAST_TO(TExampleGenerator, eg);
2640    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2641
2642    PDomain domain;
2643    if (PyArg_ParseTuple(args, "O&|i", cc_Domain, &domain))
2644      return WrapOrange(PExampleTable(mlnew TExampleTable(domain, weg)));
2645
2646    PyObject *pargs, *guard = NULL;
2647    int keepMeta = 0;
2648    if (args && ((PyTuple_Size(args)==1) || ((PyTuple_Size(args)==2) && PyInt_Check(PyTuple_GET_ITEM(args, 1))))) {
2649      pargs = guard = PyTuple_GET_ITEM(args, 0);
2650      if (PyTuple_Size(args)==2) {
2651        keepMeta = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
2652      }
2653    }
2654    else
2655      pargs = args;
2656
2657    /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2658    TVarList attributes;
2659    if (varListFromDomain(pargs, eg->domain, attributes, true, false)) {
2660      PDomain newDomain;
2661      TVarList::iterator vi, ve;
2662      for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2663      if (vi==ve)
2664        newDomain = mlnew TDomain(PVariable(), attributes);
2665      else {
2666        attributes.erase(vi);
2667        newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2668      }
2669     
2670      if (keepMeta) {
2671        newDomain->metas = eg->domain->metas;
2672      }
2673
2674      Py_XDECREF(guard);
2675      return WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2676    }
2677
2678    PYERROR(PyExc_AttributeError, "ExampleGenerator.translate expects a list of attributes or orange.Domain", PYNULL)
2679 PyCATCH
2680}
2681
2682
2683PyObject *multipleSelectLow(TPyOrange *self, PyObject *pylist, bool reference)
2684{ PyTRY
2685    if (!PyList_Check(pylist))
2686      PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2687
2688    vector<int> indices;
2689    Py_ssize_t i, sze = PyList_Size(pylist);
2690    for(i = 0; i<sze; i++) {
2691      PyObject *lel = PyList_GetItem(pylist, i);
2692      if (!PyInt_Check(lel))
2693        PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2694      indices.push_back(int(PyInt_AsLong(lel)));
2695    }
2696    sort(indices.begin(), indices.end());
2697
2698    CAST_TO(TExampleGenerator, eg);
2699    TExampleTable *newTable = reference ? mlnew TExampleTable(eg, (int)0)
2700                                        : mlnew TExampleTable(eg->domain);
2701    PExampleGenerator newGen(newTable);
2702
2703    TExampleGenerator::iterator ei(eg->begin());
2704    vector<int>::iterator ii(indices.begin()), iie(indices.end());
2705    i = 0;
2706    while(ei && (ii!=iie)) {
2707      if (*ii == i) {
2708        newTable->addExample(*ei);
2709        ii++;
2710      }
2711      else {
2712        i++;
2713        ++ei;
2714      }
2715    }
2716
2717    if (ii!=iie)
2718      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
2719
2720    return WrapOrange(newGen);
2721  PyCATCH
2722}
2723
2724
2725PyObject *ExampleGenerator_get_items(TPyOrange *self, PyObject *pylist)  PYARGS(METH_O, "(indices) -> ExampleTable")
2726{ return multipleSelectLow(self, pylist, false); }
2727
2728
2729PyObject *ExampleGenerator_checksum(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
2730{ PyTRY
2731    return PyInt_FromLong(SELF_AS(TExampleGenerator).checkSum());
2732  PyCATCH
2733}
2734
2735
2736const char *getExtension(const char *name);
2737
2738PyObject *saveTabDelimited(PyObject *, PyObject *args, PyObject *keyws);
2739PyObject *saveC45(PyObject *, PyObject *args);
2740PyObject *saveTxt(PyObject *, PyObject *args, PyObject *keyws);
2741PyObject *saveCsv(PyObject *, PyObject *args, PyObject *keyws);
2742PyObject *saveBasket(PyObject *, PyObject *args);
2743
2744PyObject *ExampleGenerator_save(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "(filename) -> None")
2745{
2746  char *filename;
2747  if (!PyArg_ParseTuple(args, "s:ExampleGenerator.save", &filename))
2748    return PYNULL;
2749
2750  const char *extension = getExtension(filename);
2751  if (!extension)
2752    PYERROR(PyExc_TypeError, "file name must have an extension", PYNULL);
2753
2754
2755  PyObject *newargs = PyTuple_New(PyTuple_Size(args) + 1);
2756  PyObject *el;
2757
2758  el = PyTuple_GET_ITEM(args, 0);
2759  Py_INCREF(el);
2760  PyTuple_SetItem(newargs, 0, el);
2761
2762  Py_INCREF(self);
2763  PyTuple_SetItem(newargs, 1, self);
2764
2765  for(Py_ssize_t i = 1, e = PyTuple_Size(args); i < e; i++) {
2766    el = PyTuple_GET_ITEM(args, i);
2767    Py_INCREF(el);
2768    PyTuple_SetItem(newargs, i+1, el);
2769  }
2770
2771  PyObject *res = PYNULL;
2772
2773  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, false, true, false);
2774  if (fi != filetypeDefinitions.end())
2775    res = PyObject_Call((*fi).saver, newargs, keyws);
2776  else if (!strcmp(extension, ".tab"))
2777    res = saveTabDelimited(NULL, newargs, keyws);
2778  else if (!strcmp(extension, ".txt"))
2779    res = saveTxt(NULL, newargs, keyws);
2780  else if (!strcmp(extension, ".csv"))
2781    res = saveCsv(NULL, newargs, keyws);
2782  else if (!strcmp(extension, ".names") || !strcmp(extension, ".data") || !strcmp(extension, ".test"))
2783    res = saveC45(NULL, newargs);
2784  else if (!strcmp(extension, ".basket"))
2785    res = saveBasket(NULL, newargs);
2786  else
2787    PyErr_Format(PyExc_AttributeError, "unknown file format (%s)", extension);
2788
2789  Py_DECREF(newargs);
2790  return res;
2791}
2792
2793
2794PyObject *ExampleGenerator_weight(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(weightID)")
2795{
2796  PyObject *pyw = PYNULL;
2797  if (!PyArg_ParseTuple(args, "|O:ExampleGenerator.weight", &pyw))
2798    return PYNULL;
2799
2800  CAST_TO(TExampleGenerator, egen)
2801  if (!pyw)
2802    return PyInt_FromLong(egen->numberOfExamples());
2803
2804  int weightID;
2805  if (!varNumFromVarDom(pyw, egen->domain, weightID))
2806    return PYNULL;
2807
2808  float weight = 0.0;
2809  PEITERATE(ei, egen)
2810    weight += WEIGHT(*ei);
2811
2812  return PyFloat_FromDouble(weight);
2813}
2814
2815
2816PExampleGeneratorList PExampleGeneratorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::P_FromArguments(arg); }
2817PyObject *ExampleGeneratorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_FromArguments(type, arg); }
2818PyObject *ExampleGeneratorList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of ExampleGenerator>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_new(type, arg, kwds); }
2819PyObject *ExampleGeneratorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getitem(self, index); }
2820int       ExampleGeneratorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_setitem(self, index, item); }
2821PyObject *ExampleGeneratorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getslice(self, start, stop); }
2822int       ExampleGeneratorList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_setslice(self, start, stop, item); }
2823Py_ssize_t       ExampleGeneratorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_len(self); }
2824PyObject *ExampleGeneratorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_richcmp(self, object, op); }
2825PyObject *ExampleGeneratorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_concat(self, obj); }
2826PyObject *ExampleGeneratorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_repeat(self, times); }
2827PyObject *ExampleGeneratorList_str(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2828PyObject *ExampleGeneratorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2829int       ExampleGeneratorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_contains(self, obj); }
2830PyObject *ExampleGeneratorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_append(self, item); }
2831PyObject *ExampleGeneratorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_extend(self, obj); }
2832PyObject *ExampleGeneratorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_count(self, obj); }
2833PyObject *ExampleGeneratorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ExampleGeneratorList") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_filter(self, args); }
2834PyObject *ExampleGeneratorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_index(self, obj); }
2835PyObject *ExampleGeneratorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_insert(self, args); }
2836PyObject *ExampleGeneratorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_native(self); }
2837PyObject *ExampleGeneratorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ExampleGenerator") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_pop(self, args); }
2838PyObject *ExampleGeneratorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_remove(self, obj); }
2839PyObject *ExampleGeneratorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reverse(self); }
2840PyObject *ExampleGeneratorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_sort(self, args); }
2841PyObject *ExampleGeneratorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reduce(self); }
2842
2843
2844/* ************ EXAMPLE TABLE ************ */
2845
2846#include "table.hpp"
2847#include "numeric_interface.hpp"
2848
2849TExampleTable *readListOfExamples(PyObject *args)
2850{
2851  if (isSomeNumeric_wPrecheck(args))
2852    return readListOfExamples(args, PDomain(), false);
2853
2854  if (PySequence_Check(args)) {
2855    Py_ssize_t size=PySequence_Size(args);
2856    if (!size)
2857      PYERROR(PyExc_TypeError, "can't construct a table from an empty sequence", (TExampleTable *)NULL);
2858
2859    TExampleTable *table=NULL;
2860    PyObject *pex = NULL;
2861
2862    try {
2863      for(Py_ssize_t i=0; i<size; i++) {
2864        PyObject *pex = PySequence_GetItem(args, i);
2865        if (!pex || !PyOrExample_Check(pex)) {
2866          Py_XDECREF(pex);
2867          mldelete table;
2868          PyErr_Format(PyExc_TypeError, "invalid sequence element at %i", i);
2869          return NULL;
2870        }
2871        if (!i)
2872          table = mlnew TExampleTable(PyExample_AS_Example(pex)->domain);
2873        table->addExample(PyExample_AS_ExampleReference(pex));
2874        Py_DECREF(pex);
2875        pex = NULL;
2876      }
2877    }
2878    catch (...) {
2879      delete table;
2880      Py_XDECREF(pex);
2881      throw;
2882    }
2883
2884    return table;
2885  }
2886
2887  PYERROR(PyExc_TypeError, "a list of examples expected", NULL);
2888}
2889
2890
2891TExampleTable *readListOfExamples(PyObject *args, PDomain domain, bool filterMetas)
2892{
2893  PyArrayObject *array = NULL, *mask = NULL;
2894
2895  if (isSomeNumeric_wPrecheck(args)) {
2896    array = (PyArrayObject *)(args);
2897  }
2898  else if (isSomeMaskedNumeric_wPrecheck(args)) {
2899    array = (PyArrayObject *)(args);
2900    mask = (PyArrayObject *)PyObject_GetAttrString(args, "mask");
2901    if (PyBool_Check((PyObject *)mask)) {
2902      Py_DECREF((PyObject *)mask);
2903      mask = NULL;
2904    }
2905  }
2906
2907  if (array) {
2908      if (array->nd != 2)
2909        PYERROR(PyExc_AttributeError, "two-dimensional array expected for an ExampleTable", NULL);
2910
2911     PVarList variables;
2912     TVarList::const_iterator vi, ve;
2913
2914      if (!domain) {
2915        TVarList lvariables;
2916        char vbuf[20];
2917        for(int i = 0, e = array->dimensions[1]; i < e; i++) {
2918          sprintf(vbuf, "a%i", i+1);
2919          lvariables.push_back(mlnew TFloatVariable(vbuf));
2920        }
2921        domain = mlnew TDomain(PVariable(), lvariables);
2922        variables = domain->variables;
2923        ve = variables->end();
2924      }
2925
2926      else {
2927        if (array->dimensions[1] != domain->variables->size())
2928          PYERROR(PyExc_AttributeError, "the number of columns in the array doesn't match the number of attributes", NULL);
2929
2930       variables = domain->variables;
2931       ve = variables->end();
2932       for(vi = variables->begin(); vi!=ve; vi++)
2933                  if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
2934                      PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
2935            }
2936
2937      const char arrayType = getArrayType(array);
2938      if (!strchr(supportedNumericTypes, arrayType)) {
2939        PyErr_Format(PyExc_AttributeError, "Converting arrays of type '%c' is not supported (use one of '%s')", arrayType, supportedNumericTypes);
2940        return NULL;
2941      }
2942
2943      TExampleTable *table = mlnew TExampleTable(domain);
2944      TExample *nex = NULL;
2945      table->reserve(array->dimensions[0]);
2946
2947      const int &strideRow = array->strides[0];
2948      const int &strideCol = array->strides[1];
2949
2950      // If there's no mask, the mask pointers will equal the data pointer to avoid too many if's
2951      const int &strideMaskRow = mask ? mask->strides[0] : strideRow;
2952      const int &strideMaskCol = mask ? mask->strides[1] : strideCol;
2953
2954      try {
2955        TExample::iterator ei;
2956        char *rowPtr = array->data;
2957        char *maskRowPtr = mask ? mask->data : array->data;
2958
2959        for(int row = 0, rowe = array->dimensions[0]; row < rowe; row++, rowPtr += strideRow, maskRowPtr += strideMaskRow) {
2960          char *elPtr = rowPtr;
2961          char *maskPtr = maskRowPtr;
2962          TExample *nex = mlnew TExample(domain);
2963
2964          #define ARRAYTYPE(TYPE) \
2965            for(ei = nex->begin(), vi = variables->begin(); vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol) \
2966              if ((*vi)->varType == TValue::INTVAR) \
2967                intValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
2968              else \
2969                floatValInit(*ei, *(TYPE *)elPtr, mask && !*maskPtr ? valueDK : valueRegular); \
2970            break;
2971
2972          switch (arrayType) {
2973            case 'c':
2974            case 'b': ARRAYTYPE(char)
2975            case 'B': ARRAYTYPE(unsigned char)
2976            case 'h': ARRAYTYPE(short)
2977            case 'H': ARRAYTYPE(unsigned short)
2978            case 'i': ARRAYTYPE(int)
2979            case 'I': ARRAYTYPE(unsigned int)
2980            case 'l': ARRAYTYPE(long)
2981            case 'L': ARRAYTYPE(unsigned long)
2982
2983            case 'f':
2984              for(ei = nex->begin(), vi = variables->begin(); vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
2985                if ((*vi)->varType == TValue::INTVAR)
2986                  intValInit(*ei, int(floor(0.5 + *(float *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
2987                else
2988                  floatValInit(*ei, *(float *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
2989              break;
2990
2991            case 'd':
2992              for(ei = nex->begin(), vi = variables->begin(); vi!=ve; vi++, ei++, elPtr += strideCol, maskPtr += strideMaskCol)
2993                if ((*vi)->varType == TValue::INTVAR)
2994                  intValInit(*ei, int(floor(0.5 + *(double *)elPtr)), mask && !*maskPtr ? valueDK : valueRegular);
2995                else
2996                  floatValInit(*ei, *(double *)elPtr, mask && !*maskPtr ? valueDK : valueRegular);
2997              break;
2998
2999          }
3000
3001          #undef ARRAYTYPE
3002
3003          table->addExample(nex);
3004          nex = NULL;
3005        }
3006      }
3007      catch (...) {
3008        mldelete table;
3009        mldelete nex;
3010        throw;
3011      }
3012
3013      return table;
3014  }
3015
3016  if (PyList_Check(args)) {
3017    Py_ssize_t size=PyList_Size(args);
3018    if (!size)
3019      PYERROR(PyExc_TypeError, "can't construct a table from an empty list", (TExampleTable *)NULL);
3020
3021    TExampleTable *table = mlnew TExampleTable(domain);;
3022
3023    try {
3024      for(Py_ssize_t i=0; i<size; i++) {
3025        PyObject *pex = PyList_GetItem(args, i);
3026        if (PyOrExample_Check(pex))
3027          table->addExample(PyExample_AS_ExampleReference(pex), filterMetas);
3028        else {
3029          TExample example(domain);
3030          if (!convertFromPythonExisting(pex, example)) {
3031            mldelete table;
3032            PyObject *type, *value, *tracebk;
3033            PyErr_Fetch(&type, &value, &tracebk);
3034            if (type) {
3035              //PyErr_Restore(type, value, tracebk);
3036              const char *oldes = PyString_AsString(value);
3037              PyErr_Format(type, "%s (at example %i)", oldes, i);
3038              Py_DECREF(type);
3039              Py_XDECREF(value);
3040              Py_XDECREF(tracebk);
3041              return NULL;
3042            }
3043          }
3044          table->addExample(example);
3045        }
3046      }
3047
3048      return table;
3049    }
3050    catch (...) {
3051      mldelete table;
3052      throw;
3053    }
3054  }
3055
3056  PYERROR(PyExc_TypeError, "invalid arguments", NULL);
3057}
3058
3059
3060CONSTRUCTOR_KEYWORDS(ExampleTable, "domain use useMetas dontCheckStored dontStore filterMetas filter_metas DC DK NA noClass noCodedDiscrete createNewOn")
3061
3062PyObject *ExampleTable_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(ExampleGenerator - Orange.data.Table, "(filename | domain[, examples] | examples)")
3063{
3064  PyTRY
3065
3066    char *filename = NULL;
3067    if (PyArg_ParseTuple(argstuple, "s", &filename))
3068      return loadDataFromFile(type, filename, argstuple, keywords, false);
3069
3070    PyErr_Clear();
3071
3072    PExampleGenerator egen;
3073    PyObject *args = PYNULL;
3074    if (PyArg_ParseTuple(argstuple, "O&|O", cc_ExampleTable, &egen, &args))
3075      return WrapNewOrange(mlnew TExampleTable(egen, !args || (PyObject_IsTrue(args) == 0)), type);
3076
3077    PyErr_Clear();
3078
3079    if (PyArg_ParseTuple(argstuple, "O", &args)) {
3080      if (PyOrDomain_Check(args))
3081        return WrapNewOrange(mlnew TExampleTable(PyOrange_AsDomain(args)), type);
3082
3083      TExampleTable *res = readListOfExamples(args);
3084      if (res)
3085        return WrapNewOrange(res, type);
3086      PyErr_Clear();
3087
3088      // check if it's a list of generators
3089      if (PyList_Check(args)) {
3090        TExampleGeneratorList eglist;
3091        PyObject *iterator = PyObject_GetIter(args);
3092        PyObject *item = PyIter_Next(iterator);
3093        for(; item; item = PyIter_Next(iterator)) {
3094          if (!PyOrExampleGenerator_Check(item)) {
3095            Py_DECREF(item);
3096            break;
3097          }
3098          eglist.push_back(PyOrange_AsExampleGenerator(item));
3099          Py_DECREF(item);
3100        }
3101        Py_DECREF(iterator);
3102        if (!item)
3103          return WrapNewOrange(mlnew TExampleTable(PExampleGeneratorList(eglist)), type);
3104      }
3105
3106      PYERROR(PyExc_TypeError, "invalid arguments for constructor (domain or examples or both expected)", PYNULL);
3107    }
3108
3109    PyErr_Clear();
3110
3111    PDomain domain;
3112    if (PyArg_ParseTuple(argstuple, "O&O", cc_Domain, &domain, &args)) {
3113      bool filterMetas = readBoolFlag(keywords, "filterMetas") || readBoolFlag(keywords, "filter_metas");
3114
3115      if (PyOrExampleGenerator_Check(args))
3116        return WrapNewOrange(mlnew TExampleTable(domain, PyOrange_AsExampleGenerator(args), filterMetas), type);
3117      else {
3118        TExampleTable *res = readListOfExamples(args, domain, filterMetas);
3119        return res ? WrapNewOrange(res, type) : PYNULL;
3120      }
3121    }
3122
3123    PYERROR(PyExc_TypeError, "invalid arguments for ExampleTable.__init__", PYNULL);
3124
3125  PyCATCH
3126}
3127
3128
3129PyObject *ExampleTable__reduce__(PyObject *self)
3130{
3131  CAST_TO(TExampleTable, table)
3132
3133  if (!table->ownsExamples || table->lock) {
3134    PExampleTable lock = table->lock;
3135    TCharBuffer buf(1024);
3136    const int lockSize = lock->size();
3137    buf.writeInt(table->size());
3138    PEITERATE(ei, table) {
3139      int index = 0;
3140      PEITERATE(li, lock) {
3141        if (&*li == &*ei)
3142          break;
3143        index++;
3144      }
3145      if (index == lockSize) {
3146        PYERROR(PyExc_SystemError, "invalid example reference discovered in the table", PYNULL);
3147      }
3148
3149      buf.writeInt(index);
3150    }
3151
3152    return Py_BuildValue("O(ONs#)O", getExportedFunction("__pickleLoaderExampleReferenceTable"),
3153                                      self->ob_type,
3154                                      WrapOrange(table->lock),
3155                                      buf.buf, buf.length(),
3156                                      packOrangeDictionary(self));
3157  }
3158
3159  else {
3160    TCharBuffer buf(1024);
3161    PyObject *otherValues = NULL;
3162
3163    buf.writeInt(table->size());
3164    PEITERATE(ei, table)
3165      Example_pack(*ei, buf, otherValues);
3166
3167    if (!otherValues) {
3168      otherValues = Py_None;
3169      Py_INCREF(otherValues);
3170    }
3171
3172    return Py_BuildValue("O(ONs#N)O", getExportedFunction("__pickleLoaderExampleTable"),
3173                                      self->ob_type,
3174                                      WrapOrange(table->domain),
3175                                      buf.buf, buf.length(),
3176                                      otherValues,
3177                                      packOrangeDictionary(self));
3178  }
3179}
3180
3181
3182PyObject *__pickleLoaderExampleTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, domain, packed_values, other_values)")
3183{
3184  PyTRY
3185    PyTypeObject *type;
3186    PDomain domain;
3187    char *buf;
3188    int bufSize;
3189    PyObject *otherValues;
3190
3191    if (!PyArg_ParseTuple(args, "OO&s#O:__pickleLoaderExampleTable", &type, cc_Domain, &domain, &buf, &bufSize, &otherValues))
3192      return NULL;
3193
3194    TCharBuffer cbuf(buf);
3195    int otherValuesIndex = 0;
3196
3197    int noOfEx = cbuf.readInt();
3198    TExampleTable *newTable = new TExampleTable(domain);
3199    try {
3200      newTable->reserve(noOfEx);
3201      for(int i = noOfEx; i--;)
3202        Example_unpack(newTable->new_example(), cbuf, otherValues, otherValuesIndex);
3203
3204      return WrapNewOrange(newTable, type);
3205    }
3206    catch (...) {
3207      delete newTable;
3208      throw;
3209    }
3210  PyCATCH
3211}
3212
3213
3214PyObject *__pickleLoaderExampleReferenceTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, lockedtable, indices)")
3215{
3216  PyTRY
3217    PyTypeObject *type;
3218    PExampleTable table;
3219    char *buf;
3220    int bufSize;
3221
3222    if (!PyArg_ParseTuple(args, "OO&s#:__pickleLoaderExampleReferenceTable", &type, cc_ExampleTable, &table, &buf, &bufSize))
3223      return NULL;
3224
3225
3226    TCharBuffer cbuf(buf);
3227    int noOfEx = cbuf.readInt();
3228
3229    TExampleTable *newTable = new TExampleTable(table, 1);
3230    try {
3231      newTable->reserve(noOfEx);
3232      for(int i = noOfEx; i--;)
3233        newTable->addExample(table->at(cbuf.readInt()));
3234      return WrapNewOrange(newTable, type);
3235    }
3236    catch (...) {
3237      delete newTable;
3238      throw;
3239    }
3240  PyCATCH
3241}
3242
3243
3244#define EXAMPLE_LOCK(tab) (((tab)->ownsExamples || !(tab)->lock) ? PExampleGenerator(tab) : (tab)->lock)
3245
3246PyObject *ExampleTable_native(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
3247{ PyTRY
3248    int natvt=2;
3249    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=3)))
3250      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
3251
3252    if (natvt<2)
3253      return ExampleGenerator_native(self, args, keywords);
3254
3255    CAST_TO(TExampleTable, table);
3256
3257    PyObject *list=PyList_New(table->numberOfExamples());
3258    Py_ssize_t i=0;
3259    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3260    EITERATE(ei, *table) {
3261      // here we wrap a reference to example, so we must pass a self's wrapper
3262      PyObject *example = Example_FromExampleRef(*ei, lock);
3263      if (!example) {
3264        PyMem_DEL(list);
3265        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3266      }
3267      PyList_SetItem(list, i++, example);
3268    }
3269
3270    return list;
3271  PyCATCH
3272}
3273
3274/*
3275PyTypeObject *gsl_matrixType = NULL;
3276
3277bool load_gsl()
3278{
3279  if (gsl_matrixType)
3280    return true;
3281
3282  PyObject *matrixModule = PyImport_ImportModule("pygsl.matrix");
3283  if (!matrixModule)
3284    return false;
3285
3286  gsl_matrixType = (PyTypeObject *)PyDict_GetItemString(PyModule_GetDict(matrixModule), "matrix");
3287  return gsl_matrixType != NULL;
3288}
3289*/
3290
3291
3292/* Not in .hpp (to be parsed by pyprops) since these only occur in arguments to numpy conversion function */
3293
3294PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Ignore, 0)
3295PYCLASSCONSTANT_INT(ExampleTable, Multinomial_AsOrdinal, 1)
3296PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Error, 2)
3297
3298
3299
3300PyObject *packMatrixTuple(PyObject *X, PyObject *y, PyObject *my, PyObject *w, char *contents)
3301{
3302  int left = (*contents && *contents != '/') ? 1 : 0;
3303
3304  char *cp = strchr(contents, '/');
3305  if (cp)
3306    cp++;
3307
3308  int right = cp ? strlen(cp) : 0;
3309
3310  PyObject *res = PyTuple_New(left + right);
3311  if (left) {
3312    Py_INCREF(X);
3313    PyTuple_SetItem(res, 0, X);
3314  }
3315
3316  if (cp)
3317    for(; *cp; cp++)
3318      if ((*cp == 'c') || (*cp == 'C')) {
3319        Py_INCREF(y);
3320        PyTuple_SetItem(res, left++, y);
3321      }
3322      else if ((*cp == 'w') || (*cp == 'W')) {
3323        Py_INCREF(w);
3324        PyTuple_SetItem(res, left++, w);
3325      }
3326      else {
3327        Py_INCREF(my);
3328        PyTuple_SetItem(res, left++, my);
3329      }
3330
3331  Py_DECREF(X);
3332  Py_DECREF(y);
3333  Py_DECREF(my);
3334  Py_DECREF(w);
3335  return res;
3336}
3337
3338
3339void parseMatrixContents(PExampleGenerator egen, const int &weightID, const char *contents, const int &multiTreatment,
3340                         bool &hasClass, bool &classVector, bool &multiclassVector, bool &weightVector, bool &classIsDiscrete, int &columns,
3341                         vector<bool> &include);
3342
3343
3344inline bool storeNumPyValue(double *&p, const TValue &val, signed char *&m, const PVariable attr, const int &row)
3345{
3346  if (val.isSpecial()) {
3347    if (m) {
3348      *p++ = 0;
3349      *m++ = 1;
3350    }
3351    else {
3352      PyErr_Format(PyExc_TypeError, "value of attribute '%s' in example '%i' is undefined", attr->get_name().c_str(), row);
3353      return false;
3354    }
3355  }
3356
3357  else if (val.varType == TValue::FLOATVAR) {
3358    *p++ = val.floatV;
3359    if (m)
3360      *m++ = 0;
3361  }
3362
3363  else if (val.varType == TValue::INTVAR) {
3364    *p++ = float(val.intV);
3365    if (m)
3366      *m++ = 0;
3367  }
3368
3369  else {
3370    *p++ = ILLEGAL_FLOAT;
3371    if (m)
3372      *m++ = 1;
3373  }
3374
3375  return true;
3376}
3377
3378
3379PyObject *ExampleTable_toNumericOrMA(PyObject *self, PyObject *args, PyObject *keywords, PyObject **module, PyObject **maskedArray = NULL)
3380{
3381  PyTRY
3382    prepareNumeric();
3383    if (!*module || maskedArray && !*maskedArray)
3384      PYERROR(PyExc_ImportError, "cannot import the necessary numeric module for conversion", PYNULL);
3385
3386    // These references are all borrowed
3387    PyObject *moduleDict = PyModule_GetDict(*module);
3388      PyObject *mzeros = PyDict_GetItemString(moduleDict, "zeros");
3389      if (!mzeros)
3390        PYERROR(PyExc_AttributeError, "numeric module has no function 'zeros'", PYNULL);
3391
3392    char *contents = NULL;
3393    int weightID = 0;
3394    int multinomialTreatment = 1;
3395    if (!PyArg_ParseTuple(args, "|sii:ExampleTable.toNumeric", &contents, &weightID, &multinomialTreatment))
3396      return PYNULL;
3397
3398    if (!contents)
3399      contents = "a/cw";
3400
3401    PExampleGenerator egen = PyOrange_AsExampleGenerator(self);
3402
3403    bool hasClass, classVector, weightVector, multiclassVector, classIsDiscrete;
3404    vector<bool> include;
3405    int columns;
3406    parseMatrixContents(egen, weightID, contents, multinomialTreatment,
3407                            hasClass, classVector, multiclassVector, weightVector,
3408                            classIsDiscrete, columns, include);
3409
3410    int rows = egen->numberOfExamples();
3411    PVariable classVar = egen->domain->classVar;
3412
3413    PyObject *X, *y, *w, *my, *mask = NULL, *masky = NULL, *maskmy = NULL;
3414    double *Xp, *yp, *myp, *wp;
3415    signed char *mp = NULL, *mpy = NULL, *mpmy = NULL;
3416    if (columns) {
3417      X = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "d");
3418      if (!X)
3419        return PYNULL;
3420
3421      Xp = (double *)((PyArrayObject *)X)->data;
3422
3423      if (maskedArray) {
3424        mask = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "b");
3425        mp = (signed char *)((PyArrayObject *)mask)->data;
3426      }
3427    }
3428    else {
3429      X = Py_None;
3430      Py_INCREF(X);
3431      Xp = NULL;
3432    }
3433
3434    if (classVector) {
3435      y = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3436      if (!y)
3437        return PYNULL;
3438      yp = (double *)((PyArrayObject *)y)->data;
3439
3440      if (maskedArray) {
3441        masky = PyObject_CallFunction(mzeros, "(i)s", rows, "b");
3442        mpy = (signed char *)((PyArrayObject *)masky)->data;
3443      }
3444    }
3445    else {
3446      y = Py_None;
3447      Py_INCREF(y);
3448      yp = NULL;
3449    }
3450
3451    if (multiclassVector) {
3452      my = PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "d");
3453      if (!my)
3454        return PYNULL;
3455      myp = (double *)((PyArrayObject *)my)->data;
3456
3457      if (maskedArray) {
3458        maskmy= PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "b");
3459        mpmy = (signed char *)((PyArrayObject *)maskmy)->data;
3460      }
3461    }
3462    else {
3463      my = Py_None;
3464      Py_INCREF(my);
3465      mpmy = NULL;
3466    }
3467
3468    if (weightVector) {
3469      w = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3470      if (!w)
3471        return PYNULL;
3472      wp = (double *)((PyArrayObject *)w)->data;
3473    }
3474    else {
3475      w = Py_None;
3476      Py_INCREF(w);
3477      wp = NULL;
3478    }
3479
3480    try {
3481      int row = 0;
3482      TExampleGenerator::iterator ei(egen->begin());
3483      for(; ei; ++ei, row++) {
3484        int col = 0;
3485
3486        /* This is all optimized assuming that each symbol (A, C, W) only appears once.
3487           If it would be common for them to appear more than once, we could cache the
3488           values, but since this is unlikely, caching would only slow down the conversion */
3489        for(const char *cp = contents; *cp && (*cp!='/'); cp++) {
3490          switch (*cp) {
3491            case 'A':
3492            case 'a': {
3493              const TVarList &attributes = egen->domain->attributes.getReference();
3494              TVarList::const_iterator vi(attributes.begin()), ve(attributes.end());
3495              TExample::iterator eei((*ei).begin());
3496              vector<bool>::const_iterator bi(include.begin());
3497              for(; vi != ve; eei++, vi++, bi++)
3498                if (*bi && !storeNumPyValue(Xp, *eei, mp, *vi, row))
3499                  return PYNULL;
3500              break;
3501            }
3502
3503            case 'C':
3504            case 'c':
3505              if (hasClass && !storeNumPyValue(Xp, (*ei).getClass(), mp, classVar, row))
3506                return PYNULL;
3507              break;
3508
3509            case 'M':
3510            case 'm': {
3511              const TVarList &classes = egen->domain->classVars.getReference();
3512              TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3513              TValue *eei = (*ei).values_end;
3514              for(; vi != ve; eei++, vi++)
3515                if (!storeNumPyValue(Xp, *eei, mp, *vi, row))
3516                  return PYNULL;
3517              break;
3518            }
3519
3520            case 'W':
3521            case 'w':
3522              if (weightID)
3523                *Xp++ = WEIGHT(*ei);
3524                if (maskedArray)
3525                  *mp++ = 0;
3526              break;
3527
3528            case '0':
3529              *Xp++ = 0.0;
3530              if (maskedArray)
3531                *mp++ = 0;
3532              break;
3533
3534            case '1':
3535              *Xp++ = 1.0;
3536              if (maskedArray)
3537                *mp++ = 0;
3538              break;
3539          }
3540        }
3541
3542        if (yp && !storeNumPyValue(yp, (*ei).getClass(), mpy, classVar, row))
3543          return PYNULL;
3544
3545        if (wp)
3546          *wp++ = WEIGHT(*ei);
3547
3548        if (myp) {
3549            const TVarList &classes = egen->domain->classVars.getReference();
3550            TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3551            TValue *eei = (*ei).values_end;
3552            for(; vi != ve; eei++, vi++)
3553              if (!storeNumPyValue(myp, *eei, mpmy, *vi, row))
3554                return PYNULL;
3555        }
3556      }
3557
3558      if (maskedArray) {
3559        PyObject *args, *maskedX = NULL, *maskedy = NULL, *maskedmy = NULL;
3560
3561        bool err = false;
3562
3563        if (mask) {
3564          args = Py_BuildValue("OOiOO", X, Py_None, 1, Py_None, mask);
3565          maskedX = PyObject_CallObject(*maskedArray, args);
3566          Py_DECREF(args);
3567          if (!maskedX) {
3568            PyErr_Clear();
3569            args = Py_BuildValue("OOOi", X, mask, Py_None, 1);
3570            maskedX = PyObject_CallObject(*maskedArray, args);
3571            Py_DECREF(args);
3572          }
3573          err = !maskedX;
3574        }
3575
3576        if (!err && masky) {
3577          args = Py_BuildValue("OOiOO", y, Py_None, 1, Py_None, masky);
3578          maskedy = PyObject_CallObject(*maskedArray, args);
3579          Py_DECREF(args);
3580          if (!maskedy) {
3581            PyErr_Clear();
3582            args = Py_BuildValue("OOOi", y, masky, Py_None, 1);
3583            maskedy = PyObject_CallObject(*maskedArray, args);
3584            Py_DECREF(args);
3585          }
3586          err = !maskedy;
3587        }
3588
3589        if (!err && maskmy) {
3590          args = Py_BuildValue("OOiOO", my, Py_None, 1, Py_None, maskmy);
3591          maskedmy = PyObject_CallObject(*maskedArray, args);
3592          Py_DECREF(args);
3593          if (!maskedmy) {
3594            PyErr_Clear();
3595            args = Py_BuildValue("OOOi", my, maskmy, Py_None, 1);
3596            maskedmy = PyObject_CallObject(*maskedArray, args);
3597            Py_DECREF(args);
3598          }
3599          err = !maskedmy;
3600        }
3601
3602        if (err) {
3603          Py_DECREF(X);
3604          Py_DECREF(y);
3605          Py_DECREF(w);
3606          Py_XDECREF(maskedX);
3607          Py_XDECREF(mask);
3608          Py_XDECREF(masky);
3609          Py_XDECREF(maskmy);
3610          return PYNULL;
3611        }
3612
3613        if (mask) {
3614          Py_DECREF(X);
3615          Py_DECREF(mask);
3616          X = maskedX;
3617        }
3618
3619        if (masky) {
3620          Py_DECREF(y);
3621          Py_DECREF(masky);
3622          y = maskedy;
3623        }
3624
3625        if (maskmy) {
3626          Py_DECREF(my);
3627          Py_DECREF(maskmy);
3628          my = maskedmy;
3629        }
3630      }
3631
3632      return packMatrixTuple(X, y, my, w, contents);
3633    }
3634    catch (...) {
3635      Py_DECREF(X);
3636      Py_DECREF(y);
3637      Py_DECREF(w);
3638      Py_XDECREF(mask);
3639      Py_XDECREF(masky);
3640      Py_XDECREF(maskmy);
3641      throw;
3642    }
3643  PyCATCH
3644}
3645
3646
3647PyObject *ExampleTable_toNumeric(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3648{
3649  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric);
3650}
3651
3652
3653PyObject *ExampleTable_toNumericMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3654{
3655  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric, &numericMaskedArray);
3656}
3657
3658// this is for compatibility
3659PyObject *ExampleTable_toMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3660{
3661  return ExampleTable_toNumericMA(self, args, keywords);
3662}
3663
3664PyObject *ExampleTable_toNumarray(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3665{
3666  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray);
3667}
3668
3669
3670PyObject *ExampleTable_toNumarrayMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3671{
3672  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray, &numarrayMaskedArray);
3673}
3674
3675PyObject *ExampleTable_toNumpy(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3676{
3677  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy);
3678}
3679
3680
3681PyObject *ExampleTable_toNumpyMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3682{
3683  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy, &numpyMaskedArray);
3684}
3685
3686
3687
3688int ExampleTable_nonzero(PyObject *self)
3689{ PyTRY
3690    return SELF_AS(TExampleGenerator).numberOfExamples() ? 1 : 0;
3691  PyCATCH_1
3692}
3693
3694Py_ssize_t ExampleTable_len_sq(PyObject *self)
3695{ PyTRY
3696    return SELF_AS(TExampleGenerator).numberOfExamples();
3697  PyCATCH_1
3698}
3699
3700
3701PyObject *ExampleTable_append(PyObject *self, PyObject *args) PYARGS(METH_O, "(example) -> None")
3702{ PyTRY
3703    CAST_TO(TExampleTable, table)
3704
3705    if (table->ownsExamples) {
3706      if (!convertFromPythonExisting(args, table->new_example())) {
3707        table->delete_last();
3708        return PYNULL;
3709      }
3710    }
3711    else {
3712      if (!PyOrExample_Check(args) || (((TPyExample *)(args))->lock != table->lock))
3713        PYERROR(PyExc_TypeError, "tables containing references to examples can only append examples from the same table", PYNULL);
3714
3715      table->addExample(PyExample_AS_ExampleReference(args));
3716    }
3717    RETURN_NONE;
3718  PyCATCH
3719}
3720
3721PyObject *ExampleTable_extend(PyObject *self, PyObject *args) PYARGS(METH_O, "(examples) -> None")
3722{ PyTRY
3723    CAST_TO(TExampleTable, table)
3724
3725    if (PyOrExampleGenerator_Check(args)) {
3726      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3727      if (args==self) {
3728        TExampleTable temp(gen, false);
3729        table->addExamples(PExampleGenerator(temp));
3730      }
3731      else {
3732        if (!table->ownsExamples
3733              && (table->lock != gen)
3734              && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3735            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3736        table->addExamples(gen);
3737      }
3738      RETURN_NONE;
3739    }
3740
3741    TExample example(table->domain);
3742    if (PyList_Check(args)) {
3743      Py_ssize_t i, size = PyList_Size(args);
3744
3745      // We won't append until we know we can append all
3746      // (don't want to leave the work half finished)
3747      if (!table->ownsExamples) {
3748        for (i = 0; i<size; i++) {
3749          PyObject *pyex = PyList_GET_ITEM(args, i);
3750          if (!PyOrExample_Check(pyex) || (((TPyExample *)(pyex))->lock != table->lock))
3751            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3752        }
3753      }
3754
3755      for(i = 0; i<size; i++) {
3756        PyObject *pex = PyList_GET_ITEM(args, i);
3757        if (!convertFromPythonExisting(pex, example))
3758          return PYNULL;
3759
3760        table->addExample(example);
3761      }
3762
3763      RETURN_NONE;
3764    }
3765
3766
3767    PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.extend", PYNULL);
3768  PyCATCH
3769}
3770
3771
3772PyObject *ExampleTable_getitem_sq(TPyOrange *self, Py_ssize_t idx)
3773{
3774  PyTRY
3775    CAST_TO(TExampleTable, table);
3776
3777    if (idx<0)
3778      idx += table->numberOfExamples();
3779
3780    if ((idx<0) || (idx>=table->numberOfExamples()))
3781      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
3782
3783    // here we wrap a reference to example, so we must pass self's wrapper
3784    return Example_FromExampleRef((*table)[idx], EXAMPLE_LOCK(PyOrange_AsExampleTable(self)));
3785  PyCATCH
3786}
3787
3788
3789int ExampleTable_setitem_sq(TPyOrange *self, Py_ssize_t idx, PyObject *pex)
3790{
3791  PyTRY
3792    CAST_TO_err(TExampleTable, table, -1);
3793
3794    if (idx>table->numberOfExamples())
3795      PYERROR(PyExc_IndexError, "index out of range", -1);
3796
3797    if (!pex) {
3798      table->erase(idx);
3799      return 0;
3800    }
3801
3802    if (!table->ownsExamples) {
3803      if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock))
3804        PYERROR(PyExc_TypeError, "tables containing references to examples can contain examples from the same table", -1);
3805
3806      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3807      return 0;
3808    }
3809
3810    if (PyOrExample_Check(pex)) {
3811      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3812      return 0;
3813    }
3814
3815    TExample example(table->domain);
3816    if (convertFromPythonExisting(pex, example)) {
3817      (*table)[idx] = example;
3818      return 0;
3819    }
3820
3821    PYERROR(PyExc_TypeError, "invalid parameter type (Example expected)", -1)
3822  PyCATCH_1
3823}
3824
3825
3826PyObject *ExampleTable_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop)
3827{
3828  PyTRY
3829    CAST_TO(TExampleTable, table);
3830
3831    if (stop>table->numberOfExamples())
3832      stop=table->numberOfExamples();
3833
3834    if (start>stop)
3835      start=stop;
3836
3837    PyObject *list=PyList_New(stop-start);
3838    Py_ssize_t i=0;
3839    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3840    while(start<stop) {
3841      // here we wrap a reference to example, so we must pass a self's wrapper
3842      PyObject *example=Example_FromExampleRef((*table)[start++], lock);
3843      if (!example) {
3844        PyMem_DEL(list);
3845        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3846      }
3847      PyList_SetItem(list, i++, (PyObject *)example);
3848    }
3849
3850    return list;
3851  PyCATCH
3852}
3853
3854
3855int ExampleTable_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *args)
3856{
3857  PyTRY
3858    CAST_TO_err(TExampleTable, table, -1);
3859
3860    if (stop>table->size())
3861      stop = table->size();
3862
3863    if (start>stop)
3864      PYERROR(PyExc_IndexError, "index out of range", -1);
3865
3866    int inspoint = stop;
3867
3868    try {
3869      if (PyOrExampleGenerator_Check(args)) {
3870        PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3871        if (args==(PyObject *)self) {
3872          TExampleTable tab(gen, false);
3873          EITERATE(ei, tab)
3874            table->insert(inspoint++, *ei);
3875        }
3876        else
3877          if (!table->ownsExamples
3878                && (table->lock != gen)
3879                && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3880              PYERROR(PyExc_TypeError, "tables containing references to examples can only contain examples from the same table", -1);
3881          PEITERATE(ei, gen)
3882            table->insert(inspoint++, *ei);
3883      }
3884
3885      else {
3886        TExample example(table->domain);
3887        if (PyList_Check(args)) {
3888          Py_ssize_t size = PyList_Size(args);
3889
3890          for(Py_ssize_t i = 0; i<size; i++) {
3891            PyObject *pex = PyList_GetItem(args, i);
3892
3893            if (table->ownsExamples) {
3894              if (!convertFromPythonExisting(pex, example)) {
3895                table->erase(stop, inspoint);
3896                return -1;
3897              }
3898              table->insert(inspoint++, example);
3899            }
3900            else {
3901              if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock)) {
3902                table->erase(stop, inspoint);
3903                PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", -1);
3904              }
3905              table->insert(inspoint++, PyExample_AS_ExampleReference(pex));
3906            }
3907          }
3908        }
3909        else
3910          PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.__setslice__", -1);
3911      }
3912    }
3913    catch (...) {
3914      table->erase(stop, inspoint);
3915      throw;
3916    }
3917
3918    table->erase(start, stop);
3919
3920    return 0;
3921  PyCATCH_1
3922}
3923
3924
3925PyObject *applyFilterL(PFilter filter, PExampleTable gen)
3926{ if (!filter)
3927    return PYNULL;
3928
3929  PyObject *list=PyList_New(0);
3930  filter->reset();
3931  PExampleGenerator lock = EXAMPLE_LOCK(gen);
3932  PEITERATE(ei, gen)
3933    if (filter->operator()(*ei)) {
3934      PyObject *obj=Example_FromExampleRef(*ei, lock);
3935      PyList_Append(list, obj);
3936      Py_DECREF(obj);
3937    }
3938
3939  return list;
3940}
3941
3942
3943PyObject *applyFilterP(PFilter filter, PExampleTable gen)
3944{ if (!filter)
3945    return PYNULL;
3946
3947  TExampleTable *newTable = mlnew TExampleTable(PExampleGenerator(gen), 1);
3948  PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
3949  filter->reset();
3950  PEITERATE(ei, gen)
3951    if (filter->operator()(*ei))
3952      newTable->addExample(*ei);
3953
3954  return WrapOrange(newGen);
3955}
3956
3957
3958PyObject *filterSelectionVectorLow(TFilter &filter, PExampleGenerator egen);
3959
3960PyObject *applyFilterB(PFilter filter, PExampleTable gen)
3961{
3962  return filter ? filterSelectionVectorLow(filter.getReference(), gen) : PYNULL;
3963}
3964
3965
3966PyObject *ExampleTable_get_items_ref(TPyOrange *self, PyObject *pylist)   PYARGS(METH_O, "(indices) -> ExampleTable")
3967{ return multipleSelectLow(self, pylist, true); }
3968
3969
3970PyObject *ExampleTable_selectLow(TPyOrange *self, PyObject *args, PyObject *keywords, const int toList)
3971{
3972  PyTRY
3973    CAST_TO(TExampleTable, eg);
3974    PExampleGenerator weg = PExampleGenerator(PyOrange_AS_Orange(self));
3975    PExampleGenerator lock = EXAMPLE_LOCK(eg);
3976
3977    /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
3978    /* Deprecated: use 'filter' instead */
3979    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
3980      switch (toList) {
3981        case 2: return applyFilterB(filter_sameValues(keywords, eg->domain), weg);
3982        case 1: return applyFilterL(filter_sameValues(keywords, eg->domain), weg);
3983        default: return applyFilterP(filter_sameValues(keywords, eg->domain), weg);
3984      }
3985    }
3986
3987    PyObject *mplier;
3988    int index;
3989    if (PyArg_ParseTuple(args, "O|i", &mplier, &index)) {
3990      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
3991      bool negate = pyneg && PyObject_IsTrue(pyneg);
3992      bool indexGiven = (PyTuple_Size(args)==2);
3993
3994      /* ***** SELECTION BY PYLIST ****** */
3995      if (PyList_Check(mplier)) {
3996        if (PyList_Size(mplier) != eg->numberOfExamples())
3997          PYERROR(PyExc_IndexError, "example selector of invalid length", PYNULL);
3998
3999        int i = 0;
4000        switch (toList) {
4001
4002          case 1: {
4003            PyObject *list = PyList_New(0);
4004
4005            if (indexGiven)
4006              EITERATE(ei, *eg) {
4007                PyObject *lel = PyList_GetItem(mplier, i++);
4008                if (!PyInt_Check(lel))
4009                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4010
4011                if (negate != (index==PyInt_AsLong(lel))) {
4012                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4013                  PyList_Append(list, pyex);
4014                  Py_DECREF(pyex);
4015                }
4016              }
4017            else
4018              EITERATE(ei, *eg)
4019                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0)) {
4020                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4021                  PyList_Append(list, pyex);
4022                  Py_DECREF(pyex);
4023                }
4024
4025            return list;
4026          }
4027
4028
4029          // this is a pervesion, but let's support it as a kind of syntactic sugar...
4030          case 2: {
4031            const Py_ssize_t lsize = PyList_Size(mplier);
4032            TBoolList *selection = new TBoolList(lsize);
4033            PBoolList pselection = selection;
4034            TBoolList::iterator si(selection->begin());
4035            if (indexGiven)
4036              for(Py_ssize_t i = 0; i < lsize; i++) {
4037                PyObject *lel = PyList_GetItem(mplier, i);
4038                if (!PyInt_Check(lel))
4039                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4040
4041                *si++ = negate != (index == PyInt_AsLong(lel));
4042              }
4043            else
4044              for(Py_ssize_t i = 0; i < lsize; *si++ = negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0));
4045
4046            return WrapOrange(pselection);
4047          }
4048
4049
4050          default: {
4051            TExampleTable *newTable = mlnew TExampleTable(lock, 1); //locks to weg but does not copy
4052            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4053
4054            if (indexGiven)
4055              EITERATE(ei, *eg) {
4056                PyObject *lel = PyList_GetItem(mplier, i++);
4057                if (!PyInt_Check(lel))
4058                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4059
4060                if (negate != (index==PyInt_AsLong(lel)))
4061                  newTable->addExample(*ei);
4062              }
4063            else
4064              EITERATE(ei, *eg)
4065                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0))
4066                  newTable->addExample(*ei);
4067
4068            return WrapOrange(newGen);
4069          }
4070        }
4071      }
4072
4073      /* ***** SELECTION BY LONGLIST ****** */
4074      else if (PyOrLongList_Check(mplier)) {
4075        PLongList llist = PyOrange_AsLongList(mplier);
4076        if (int(llist->size()) != eg->numberOfExamples())
4077          PYERROR(PyExc_IndexError, "select: invalid list size", PYNULL)
4078
4079        TLongList::iterator lli(llist->begin()), lle(llist->end());
4080        TExampleIterator ei = eg->begin();
4081
4082        switch (toList) {
4083          case 1: {
4084            PyObject *list = PyList_New(0);
4085            for(; ei && (lli!=lle); ++ei, lli++)
4086              if (negate != (indexGiven ? (*lli==index) : (*lli!=0))) {
4087                PyObject *pyex = Example_FromExampleRef(*ei, lock);
4088                PyList_Append(list, pyex);
4089                Py_DECREF(pyex);
4090              }
4091            return list;
4092          }
4093
4094          case 2: {
4095            TBoolList *selection = new TBoolList(llist->size());
4096            PBoolList pselection = selection;
4097            for(TBoolList::iterator si(selection->begin()); lli != lle; *si++ = negate != (indexGiven ? (*lli++ == index) : (*lli++ != 0)));
4098
4099            return WrapOrange(pselection);
4100          }
4101
4102          default: {
4103            TExampleTable *newTable = mlnew TExampleTable(lock, 1);
4104            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4105
4106            for(;ei && (lli!=lle); ++ei, lli++)
4107              if (negate != (indexGiven ? (*lli==index) : (*lli!=0)))
4108                newTable->addExample(*ei);
4109
4110            return WrapOrange(newGen);
4111          }
4112        }
4113      }
4114
4115      PyErr_Clear();
4116
4117
4118      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
4119      /* Deprecated: use method 'filter' instead. */
4120      if (PyDict_Check(mplier))
4121        switch (toList) {
4122          case 2: return applyFilterB(filter_sameValues(mplier, eg->domain), weg);
4123          case 1: return applyFilterL(filter_sameValues(mplier, eg->domain), weg);
4124          default: return applyFilterP(filter_sameValues(mplier, eg->domain), weg);
4125        }
4126
4127      else if (PyOrFilter_Check(mplier))
4128        switch (toList) {
4129          case 2: return applyFilterB(PyOrange_AsFilter(mplier), weg);
4130          case 1: return applyFilterL(PyOrange_AsFilter(mplier), weg);
4131          default: return applyFilterP(PyOrange_AsFilter(mplier), weg);
4132        }
4133    }
4134
4135  PYERROR(PyExc_TypeError, "invalid example selector type", PYNULL);
4136  PyCATCH
4137}
4138
4139
4140PyObject *ExampleTable_select_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4141{ PyTRY
4142    return ExampleTable_selectLow(self, args, keywords, 1);
4143  PyCATCH
4144}
4145
4146
4147PyObject *ExampleTable_select_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4148{ PyTRY
4149    return ExampleTable_selectLow(self, args, keywords, 0);
4150  PyCATCH
4151}
4152
4153
4154PyObject *ExampleTable_select_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4155{ PyTRY
4156    return ExampleTable_selectLow(self, args, keywords, 2);
4157  PyCATCH
4158}
4159
4160
4161PyObject *ExampleTable_filter_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4162{
4163  PyTRY
4164    CAST_TO(TExampleGenerator, eg);
4165    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4166
4167    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4168      return applyFilterL(filter_sameValues(keywords, eg->domain, keywords), weg);
4169    }
4170
4171    if (PyTuple_Size(args)==1) {
4172      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4173
4174      if (PyDict_Check(arg))
4175        return applyFilterL(filter_sameValues(arg, eg->domain, keywords), weg);
4176
4177      if (PyOrFilter_Check(arg))
4178          return applyFilterL(PyOrange_AsFilter(arg), weg);
4179    }
4180
4181    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_list expects a list of conditions or orange.Filter", PYNULL)
4182  PyCATCH
4183}
4184
4185
4186PyObject *ExampleTable_filter_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4187{
4188  PyTRY
4189    CAST_TO(TExampleGenerator, eg);
4190    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4191
4192    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4193      return applyFilterP(filter_sameValues(keywords, eg->domain, keywords), weg);
4194    }
4195
4196    if (PyTuple_Size(args)==1) {
4197      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4198
4199      if (PyDict_Check(arg))
4200        return applyFilterP(filter_sameValues(arg, eg->domain, keywords), weg);
4201
4202      if (PyOrFilter_Check(arg))
4203          return applyFilterP(PyOrange_AsFilter(arg), weg);
4204    }
4205
4206    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_ref expects a list of conditions or orange.Filter", PYNULL)
4207  PyCATCH
4208}
4209
4210
4211PyObject *ExampleTable_filter_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4212{
4213  PyTRY
4214    CAST_TO(TExampleGenerator, eg);
4215    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4216
4217    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4218      return applyFilterB(filter_sameValues(keywords, eg->domain, keywords), weg);
4219    }
4220
4221    if (PyTuple_Size(args)==1) {
4222      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4223
4224      if (PyDict_Check(arg))
4225        return applyFilterB(filter_sameValues(arg, eg->domain, keywords), weg);
4226
4227      if (PyOrFilter_Check(arg))
4228          return applyFilterB(PyOrange_AsFilter(arg), weg);
4229    }
4230
4231    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_bool expects a list of conditions or orange.Filter", PYNULL)
4232  PyCATCH
4233}
4234
4235
4236PyObject *ExampleTable_random_example(TPyOrange *self) PYARGS(0, "() -> Example")
4237{ PyTRY
4238    CAST_TO(TExampleTable, table);
4239    TExample example(table->domain);
4240    table->randomExample(example);
4241    return Example_FromExampleCopyRef(example);
4242  PyCATCH
4243}
4244
4245
4246PyObject *ExampleTable_removeDuplicates(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([weightID=0]]) -> None")
4247{ PyTRY
4248    if (PyTuple_Size(args) > 1)
4249      PYERROR(PyExc_AttributeError, "at most one argument (weight) expected", PYNULL);
4250
4251    CAST_TO(TExampleTable, table);
4252
4253    int weightID = 0;
4254    if (PyTuple_Size(args) && !weightFromArg_byDomain(PyTuple_GET_ITEM(args, 0), table->domain, weightID))
4255      return PYNULL;
4256
4257    table->removeDuplicates(weightID);
4258    RETURN_NONE;
4259  PyCATCH
4260}
4261
4262
4263PyObject *ExampleTable_shuffle(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None")
4264{
4265  PyTRY
4266    SELF_AS(TExampleTable).shuffle();
4267    RETURN_NONE;
4268  PyCATCH
4269}
4270
4271PyObject *ExampleTable_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> None")
4272{ PyTRY
4273    CAST_TO(TExampleTable, table);
4274
4275    if (!args || !PyTuple_Size(args)) {
4276      table->sort();
4277      RETURN_NONE;
4278    }
4279
4280    PyObject *alist = PyTuple_GET_ITEM(args, 0);
4281    /* If the first argument is nor list nor tuple, the whole argument is taken as a list
4282       i.e., data.sort("age", "prescr") is interpreted the same as data.sort(["age", "prescr"])
4283       All references are borrowed. */
4284    if ((PyTuple_Size(args) > 1) || (!PyList_Check(alist) && !PyTuple_Check(alist)))
4285      alist = args;
4286
4287    TVarList attributes;
4288    if (varListFromDomain(alist, table->domain, attributes, true, true)) {
4289      vector<int> order;
4290      for(TVarList::reverse_iterator vi(attributes.rbegin()), ve(attributes.rend()); vi!=ve; vi++)
4291        order.push_back(table->domain->getVarNum(*vi));
4292      table->sort(order);
4293      RETURN_NONE;
4294    }
4295
4296    PYERROR(PyExc_TypeError, "invalid arguments (none, or a list of attributes expected)", PYNULL);
4297
4298  PyCATCH
4299}
4300
4301
4302PyObject *ExampleTable_addMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id[, Value=1.0]) -> None")
4303{ PyTRY
4304    CAST_TO(TExampleTable, table);
4305
4306    PyObject *pyid;
4307    PyObject *pyvalue=PYNULL;
4308    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4309      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4310
4311    int id;
4312    PVariable metavariable;
4313    if (PyInt_Check(pyid)) {
4314      id = PyInt_AsLong(pyid);
4315      metavariable = table->domain->getMetaVar(id, false);
4316    }
4317    else if (PyString_Check(pyid)) {
4318      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4319      metavariable = table->domain->getMetaVar(id, false);
4320    }
4321    else if (PyOrVariable_Check(pyid)) {
4322      metavariable = PyOrange_AsVariable(pyid);
4323      id = table->domain->getMetaNum(metavariable);
4324    }
4325
4326    TValue value;
4327    if (!pyvalue)
4328      if (metavariable && metavariable->varType != TValue::FLOATVAR)
4329        value = metavariable->DK();
4330      else
4331        value = TValue(float(1.0));
4332    else if (!convertFromPython(pyvalue, value, metavariable))
4333      PYERROR(PyExc_AttributeError, "invalid value argument", PYNULL);
4334
4335    table->addMetaAttribute(id, value);
4336
4337    RETURN_NONE;
4338  PyCATCH
4339}
4340
4341
4342PyObject *ExampleTable_removeMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id) -> None")
4343{ PyTRY
4344    CAST_TO(TExampleTable, table);
4345
4346    PyObject *pyid;
4347    PyObject *pyvalue=PYNULL;
4348    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4349      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4350
4351    int id;
4352    if (PyInt_Check(pyid))
4353      id = PyInt_AsLong(pyid);
4354    else if (PyString_Check(pyid))
4355      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4356    else if (PyOrVariable_Check(pyid))
4357      id = table->domain->getMetaNum(PyOrange_AsVariable(pyid));
4358
4359    table->removeMetaAttribute(id);
4360
4361    RETURN_NONE;
4362  PyCATCH
4363}
4364
4365
4366PyObject *ExampleTable_changeDomain(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(Domain) -> None")
4367{ PyTRY
4368    CAST_TO(TExampleTable, table);
4369    if (!table->ownsExamples)
4370      PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4371
4372    PDomain domain;
4373    if (!PyArg_ParseTuple(args, "O&", cc_Domain, &domain))
4374      PYERROR(PyExc_AttributeError, "domain argument expected", PYNULL);
4375
4376    table->changeDomain(domain);
4377    RETURN_NONE;
4378  PyCATCH
4379}
4380
4381PyObject *ExampleTable_pickClass(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable | name) -> None")
4382{
4383    PyTRY
4384        CAST_TO(TExampleTable, table);
4385        if (!table->ownsExamples) {
4386            PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4387        }
4388        PVariable newClass;
4389        if (PyString_Check(obj)) {
4390            const char *attr = PyString_AS_STRING(obj);
4391            TVarList::const_iterator mci(table->domain->classVars->begin()), mce(table->domain->classVars->end());
4392            for(; (mci != mce) && ((*mci)->get_name() != attr); mci++);
4393            if (mci == mce) {
4394                PYERROR(PyExc_TypeError, "table does not have multiple classes", PYNULL);
4395            }
4396            newClass = *mci;
4397        }
4398        if (PyOrVariable_Check(obj)) {
4399            newClass = PyOrange_AsVariable(obj);
4400        }
4401        else if (obj != Py_None) {
4402            PYERROR(PyExc_TypeError, "class should be given as Variable, name or None", PYNULL);
4403        }
4404        table->pickClass(newClass);
4405        RETURN_NONE;
4406    PyCATCH;
4407}
4408
4409
4410
4411PyObject *ExampleTable_hasMissingValues(TPyOrange *self) PYARGS(0, "() -> bool")
4412{
4413  PyTRY
4414    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissing());
4415  PyCATCH
4416}
4417
4418
4419PyObject *ExampleTable_hasMissingClasses(TPyOrange *self) PYARGS(0, "() -> bool")
4420{
4421  PyTRY
4422    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissingClass());
4423  PyCATCH
4424}
4425/* ************ TRANSFORMVALUE ************ */
4426
4427#include "transval.hpp"
4428BASED_ON(TransformValue, Orange)
4429
4430PyObject *TransformValue_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
4431{ if (type == (PyTypeObject *)&PyOrTransformValue_Type)
4432    return setCallbackFunction(WrapNewOrange(mlnew TTransformValue_Python(), type), args);
4433  else
4434    return WrapNewOrange(mlnew TTransformValue_Python(), type);
4435}
4436
4437
4438PyObject *TransformValue__reduce__(PyObject *self)
4439{
4440  return callbackReduce(self, PyOrTransformValue_Type);
4441}
4442
4443
4444PyObject *TransformValue_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(value) -> Value")
4445{ PyTRY
4446    NO_KEYWORDS
4447
4448    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrTransformValue_Type) {
4449      PyErr_Format(PyExc_SystemError, "TransformValue.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
4450      return PYNULL;
4451    }
4452
4453    CAST_TO(TTransformValue, tv)
4454
4455    TPyValue *value;
4456    if (!convertFromPython(args, value))
4457      return PYNULL;
4458
4459    tv->transform(value->value);
4460    value->variable=PVariable();
4461    return (PyObject *)value;
4462  PyCATCH
4463}
4464
4465
4466/* ************ DISTRIBUTION ************ */
4467
4468#include "distvars.hpp"
4469
4470PyObject *convertToPythonNative(const TDiscDistribution &disc)
4471{ int e = disc.size();
4472  PyObject *pylist = PyList_New(e);
4473  for (Py_ssize_t i = 0; i<e; i++)
4474    PyList_SetItem(pylist, i, PyFloat_FromDouble((double)(disc[i])));
4475  return pylist;
4476}
4477
4478PyObject *convertToPythonNative(const TContDistribution &cont)
4479{ PyObject *pydict = PyDict_New();
4480  const_ITERATE(TContDistribution, ci, cont) {
4481    PyObject *key = PyFloat_FromDouble((double)((*ci).first));
4482    PyObject *val = PyFloat_FromDouble((double)((*ci).second));
4483    PyDict_SetItem(pydict, key, val);
4484    Py_DECREF(key);
4485    Py_DECREF(val);
4486  }
4487  return pydict;
4488}
4489
4490
4491bool convertFromPython(PyObject *pylist, TDiscDistribution &disc)
4492{
4493  if (!PyList_Check(pylist))
4494    PYERROR(PyExc_TypeError, "list expected", false);
4495
4496  disc.clear();
4497  float d;
4498  for(Py_ssize_t i = 0, e = PyList_Size(pylist); i!=e; i++) {
4499    if (!PyNumber_ToFloat(PyList_GET_ITEM(pylist, i), d))
4500      PYERROR(PyExc_TypeError, "non-number in DiscDistribution as list", false);
4501    disc.set(TValue((int)i), d);
4502  }
4503
4504  return true;
4505}
4506
4507
4508PyObject *convertToPythonNative(const TDistribution &dist, int)
4509{ const TDiscDistribution *disc = dynamic_cast<const TDiscDistribution *>(&dist);
4510  if (disc)
4511    return convertToPythonNative(*disc);
4512
4513  const TContDistribution *cont = dynamic_cast<const TContDistribution *>(&dist);
4514  if (cont)
4515    return convertToPythonNative(*cont);
4516
4517  PYERROR(PyExc_TypeError, "cannot convert to native python object", PYNULL);
4518}
4519
4520
4521/* Class Distribution has a constructor, but it constructs an instance of either DiscDistribution
4522   or ContDistribution. Class Distribution is thus essentially abstract for Python, although it has
4523   a constructor. */
4524
4525NO_PICKLE(Distribution)
4526
4527PyObject *Distribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(SomeValue - Orange.statistics.distribution.Distribution, "(attribute[, examples[, weightID]])")
4528{
4529  PyTRY
4530    PExampleGenerator gen;
4531    PyObject *pyvar;
4532    int weightID = 0;
4533    if (!PyArg_ParseTuple(args, "O|O&O&:Distribution.new", &pyvar, &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID))
4534      return PYNULL;
4535
4536    TDistribution *dist;
4537
4538    if (!gen) {
4539      if (PyOrVariable_Check(pyvar))
4540        dist = TDistribution::create(PyOrange_AsVariable(pyvar));
4541      else if (PyList_Check(pyvar)) {
4542        TDiscDistribution *ddist = mlnew TDiscDistribution();
4543        if (!convertFromPython(pyvar, *ddist)) {
4544          mldelete ddist;
4545          raiseError("invalid arguments");
4546        }
4547        else
4548          dist = ddist;
4549      }
4550      else
4551        raiseError("invalid arguments");
4552    }
4553    else {
4554      if (PyOrVariable_Check(pyvar))
4555        dist = TDistribution::fromGenerator(gen, PyOrange_AsVariable(pyvar), weightID);
4556      else {
4557        PVariable var = varFromArg_byDomain(pyvar, gen->domain, false);
4558        if (!var)
4559          return PYNULL;
4560
4561        dist = TDistribution::fromGenerator(gen, var, weightID);
4562      }
4563    }
4564
4565    /* We need to override the type (don't want to lie it's Distribution).
4566       The exception is if another type is prescribed. */
4567    return type==(PyTypeObject *)(&PyOrDistribution_Type) ? WrapOrange(PDistribution(dist)) : WrapNewOrange(dist, type);
4568  PyCATCH
4569}
4570
4571
4572PyObject *Distribution_native(PyObject *self, PyObject *) PYARGS(0, "() -> list | dictionary")
4573{
4574  PyTRY
4575    return convertToPythonNative(*PyOrange_AS_Orange(self).AS(TDistribution), 1);
4576  PyCATCH
4577}
4578
4579
4580TDiscDistribution *getDiscDistribution(PyObject *self)
4581{ TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4582  if (!disc)
4583    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected DiscDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4584  return disc;
4585}
4586
4587
4588TContDistribution *getContDistribution(PyObject *self)
4589{ TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4590  if (!cont)
4591    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected ContDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4592  return cont;
4593}
4594
4595
4596
4597float *Distribution_getItemRef(PyObject *self, PyObject *index, float *float_idx=NULL)
4598{
4599  TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4600  if (disc) {
4601    int ind=-1;
4602    if (PyInt_Check(index))
4603      ind = (int)PyInt_AsLong(index);
4604    else {
4605      if (!disc->variable)
4606        PYERROR(PyExc_SystemError, "invalid distribution (no variable)", (float *)NULL);
4607      TValue val;
4608      if (convertFromPython(index, val, disc->variable) && !val.isSpecial())
4609        ind=int(val);
4610    }
4611
4612    if (ind<0)
4613      PYERROR(PyExc_IndexError, "invalid index for distribution", (float *)NULL);
4614
4615    if (ind<int(disc->size()))
4616      return &disc->at(ind);
4617
4618    PyErr_Format(PyExc_IndexError, "index %i is out of range (0-%i)", ind, disc->size()-1);
4619    return (float *)NULL;
4620  }
4621
4622  TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4623  if (cont) {
4624    float ind;
4625    if (PyNumber_ToFloat(index, ind)) {
4626      if (float_idx)
4627        *float_idx = ind;
4628    }
4629    else {
4630      TValue val;
4631      if (convertFromPython(index, val, cont->variable) && !val.isSpecial()) {
4632        ind = float(val);
4633        if (float_idx)
4634          *float_idx = ind;
4635      }
4636      else
4637        PYERROR(PyExc_IndexError, "invalid index type (float expected)", NULL);
4638    }
4639
4640    TContDistribution::iterator mi=cont->find(ind);
4641    if (mi!=cont->end())
4642      return &(*mi).second;
4643  }
4644
4645  PYERROR(PyExc_IndexError, "invalid index", (float *)NULL);
4646}
4647
4648
4649PyObject *Distribution_getitem(PyObject *self, PyObject *index)
4650{ PyTRY
4651    float *prob=Distribution_getItemRef(self, index);
4652    return prob ? PyFloat_FromDouble(*prob) : PYNULL;
4653  PyCATCH
4654}
4655
4656
4657int Distribution_setitem(PyObject *self, PyObject *index, PyObject *item)
4658{ PyTRY
4659    PyObject *flt = PyNumber_Float(item);
4660    if (!flt)
4661      PYERROR(PyExc_TypeError, "float expected", -1);
4662
4663    float val=(float)PyFloat_AsDouble(flt);
4664    Py_DECREF(flt);
4665
4666    if (PyOrValue_Check(index)) {
4667      SELF_AS(TDistribution).set(PyValue_AS_Value(index), val);
4668      return 0;
4669    }
4670
4671    float *prob = Distribution_getItemRef(self, index);
4672    if (!prob)
4673      return -1;
4674
4675    *prob = val;
4676    return 0;
4677  PyCATCH_1
4678}
4679
4680
4681string convertToString(const PDistribution &distribution)
4682{
4683  const TDiscDistribution *disc = distribution.AS(TDiscDistribution);
4684  if (disc) {
4685    string res = "<";
4686    char buf[128];
4687    const_PITERATE(TDiscDistribution, di, disc) {
4688      if (res.size()>1)
4689        res += ", ";
4690      sprintf(buf, "%.3f", *di);
4691      res += buf;
4692    }
4693    return res+">";
4694  }
4695
4696  const TContDistribution *cont = distribution.AS(TContDistribution);
4697  if (cont) {
4698    string res = "<";
4699    char buf[128];
4700    const_PITERATE(TContDistribution, di, cont) {
4701      if (res.size()>1)
4702        res += ", ";
4703      sprintf(buf, "%.3f: %.3f", (*di).first, (*di).second);
4704      res += buf;
4705    }
4706    return res+">";
4707  }
4708
4709  raiseErrorWho("convertToString(PDistribution)", "invalid distribution");
4710  return string();
4711}
4712
4713
4714PyObject *Distribution_str(PyObject *self)
4715{ PyTRY
4716    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "str", "repr");
4717    if (result)
4718      return result;
4719
4720    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4721  PyCATCH
4722}
4723
4724
4725PyObject *Distribution_repr(PyObject *self)
4726{ PyTRY
4727    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "repr", "str");
4728    if (result)
4729      return result;
4730
4731    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4732  PyCATCH
4733}
4734
4735
4736PyObject *Distribution_normalize(PyObject *self) PYARGS(0, "() -> None")
4737{ PyTRY
4738    SELF_AS(TDistribution).normalize();
4739    RETURN_NONE;
4740  PyCATCH
4741}
4742
4743
4744PyObject *Distribution_modus(PyObject *self) PYARGS(0, "() -> Value")
4745{ PyTRY
4746    CAST_TO(TDistribution, dist)
4747    return Value_FromVariableValue(dist->variable, dist->highestProbValue());
4748  PyCATCH
4749}
4750
4751
4752PyObject *Distribution_random(PyObject *self) PYARGS(0, "() -> Value")
4753{ PyTRY
4754    CAST_TO(TDistribution, dist)
4755    return Value_FromVariableValue(dist->variable, dist->randomValue());
4756  PyCATCH
4757}
4758
4759
4760
4761PDiscDistribution list2discdistr(PyObject *args, PyTypeObject *type = NULL)
4762{
4763  TDiscDistribution *udist = mlnew TDiscDistribution();
4764  PDiscDistribution disc = type ? PDistribution(udist) : PDistribution(udist, type);
4765  for(Py_ssize_t i = 0, e = PyList_Size(args); i<e; i++) {
4766    PyObject *flt = PyNumber_Float(PyList_GetItem(args, i));
4767    if (!flt) {
4768      PyErr_Format(PyExc_TypeError, "invalid element at index %i (float expected)", i);
4769      return PDiscDistribution();
4770    }
4771    udist->addint((int)i, (float)PyFloat_AsDouble(flt));
4772    Py_DECREF(flt);
4773  }
4774
4775  return disc;
4776}
4777
4778
4779PyObject *DiscDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Discrete, "[list of floats] | DiscDistribution")
4780{ PyTRY {
4781    if (!PyTuple_Size(targs)) {
4782      return WrapNewOrange(mlnew TDiscDistribution(), type);
4783    }
4784
4785    if (PyTuple_Size(targs)==1) {
4786      PyObject *args = PyTuple_GetItem(targs, 0);
4787
4788      if (PyList_Check(args)) {
4789        PDiscDistribution disc = list2discdistr(args, type);
4790        if (disc)
4791          return WrapOrange(disc);
4792      }
4793
4794      else if (PyOrDiscDistribution_Check(args)) {
4795        Py_INCREF(args);
4796        return args;
4797      }
4798
4799      else if (PyOrEnumVariable_Check(args))
4800        return WrapNewOrange(mlnew TDiscDistribution(PyOrange_AsVariable(args)), type);
4801    }
4802
4803    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
4804  }
4805  PyCATCH;
4806}
4807
4808
4809PyObject *DiscDistribution__reduce__(PyObject *self)
4810{
4811  PyTRY
4812    TDiscDistribution *disc = getDiscDistribution(self);
4813    TCharBuffer buf(sizeof(float)*(disc->size()+2));
4814    buf.writeFloatVector(disc->distribution);
4815
4816    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderDiscDistribution"),
4817                                    self->ob_type,
4818                                    buf.buf, buf.length(),
4819                                    packOrangeDictionary(self));
4820  PyCATCH
4821}
4822
4823
4824PyObject *__pickleLoaderDiscDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
4825{
4826  PyTRY
4827    PyTypeObject *type;
4828    char *buf;
4829    int bufSize;
4830    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &buf, &bufSize))
4831      return PYNULL;
4832
4833    const int &size = (int &)*buf;
4834    buf += sizeof(int);
4835
4836    return WrapNewOrange(new TDiscDistribution((float *)buf, size), type);
4837  PyCATCH
4838}
4839
4840
4841int pt_DiscDistribution(PyObject *args, void *dist)
4842{ if (PyOrDiscDistribution_Check(args)) {
4843    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4844    return 1;
4845  }
4846  else if (PyList_Check(args)) {
4847    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4848    if (dist)
4849      return 1;
4850  }
4851
4852  PYERROR(PyExc_TypeError, "invalid discrete distribution", 0)
4853}
4854
4855
4856PyObject *DiscDistribution_getitem_sq(PyObject *self, Py_ssize_t ind)
4857{
4858  PyTRY
4859    TDiscDistribution *disc = getDiscDistribution(self);
4860    if (!disc)
4861      return PYNULL;
4862
4863    if ((ind<0) || (ind>=disc->size()))
4864      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
4865
4866    return PyFloat_FromDouble(double(disc->at(ind)));
4867  PyCATCH
4868}
4869
4870
4871Py_ssize_t DiscDistribution_len(PyObject *self)
4872{ PyTRY
4873    TDiscDistribution *disc = getDiscDistribution(self);
4874    return disc ? disc->size() : -1;
4875  PyCATCH_1
4876}
4877
4878
4879PyObject *DiscDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
4880{ PyTRY
4881    TDiscDistribution *disc = getDiscDistribution(self);
4882    if (!disc)
4883      return PYNULL;
4884
4885    if (!disc->variable)
4886      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4887
4888    PyObject *nl=PyList_New(disc->variable->noOfValues());
4889    Py_ssize_t i=0;
4890    PStringList vals=disc->variable.AS(TEnumVariable)->values;
4891    PITERATE(TStringList, ii, vals)
4892      PyList_SetItem(nl, i++, PyString_FromString((*ii).c_str()));
4893    return nl;
4894  PyCATCH
4895}
4896
4897
4898PyObject *DiscDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
4899{ PyTRY
4900    TDiscDistribution *disc = getDiscDistribution(self);
4901    if (!disc)
4902      return PYNULL;
4903
4904    if (!disc->variable)
4905      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
4906
4907    PyObject *nl=PyList_New(disc->variable->noOfValues());
4908    TDiscDistribution::const_iterator ci(disc->begin());
4909    Py_ssize_t i=0;
4910    PStringList vals=disc->variable.AS(TEnumVariable)->values;
4911    PITERATE(TStringList, ii, vals)
4912      PyList_SetItem(nl, i++, Py_BuildValue("sf", (*ii).c_str(), *(ci++)));
4913    return nl;
4914  PyCATCH
4915}
4916
4917
4918PyObject *DiscDistribution_values(PyObject *self) PYARGS(0, "() -> list")
4919{ PyTRY
4920    TDiscDistribution *disc = getDiscDistribution(self);
4921    if (!disc)
4922      return PYNULL;
4923
4924    PyObject *nl = PyList_New(disc->size());
4925    Py_ssize_t i = 0;
4926    const_PITERATE(TDiscDistribution, ci, disc)
4927      PyList_SetItem(nl, i++, PyFloat_FromDouble(*ci));
4928    return nl;
4929  PyCATCH
4930}
4931
4932
4933PyObject *DiscDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
4934{ PyTRY
4935    CAST_TO(TDiscDistribution, dist)
4936
4937    PyObject *index;
4938    float weight = 1.0;
4939    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
4940      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
4941
4942    if (PyInt_Check(index)) {
4943      dist->addint(int(PyInt_AsLong(index)), weight);
4944      RETURN_NONE;
4945    }
4946
4947    TValue val;
4948    if (!dist->variable || !convertFromPython(index, val, dist->variable))
4949      PYERROR(PyExc_TypeError, "DiscDistriubtion.add: cannot convert the arguments to a Value", PYNULL);
4950
4951    dist->add(val, weight);
4952    RETURN_NONE;
4953  PyCATCH;
4954}
4955
4956
4957PyObject *ContDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Continuous, "[dist of float:float] | DiscDistribution")
4958{ PyTRY {
4959
4960    if (!PyTuple_Size(targs))
4961      return WrapNewOrange(mlnew TContDistribution(), type);
4962
4963    if (PyTuple_Size(targs) == 1) {
4964      PyObject *args = PyTuple_GetItem(targs, 0);
4965
4966      if (PyDict_Check(args)) {
4967        TContDistribution *udist = mlnew TContDistribution();
4968        PContDistribution cont = PDistribution(udist);
4969        PyObject *key, *value;
4970        Py_ssize_t pos = 0;
4971        while (PyDict_Next(args, &pos, &key, &value)) {
4972          PyObject *flt = PyNumber_Float(key);
4973          if (!flt) {
4974            PyErr_Format(PyExc_TypeError, "invalid key at index %i (float expected)", pos);
4975            return false;
4976          }
4977          float ind = (float) PyFloat_AsDouble(flt);
4978          Py_DECREF(flt);
4979
4980          flt = PyNumber_Float(value);
4981          if (!flt) {
4982            PyErr_Format(PyExc_TypeError, "invalid value at index %i (float expected)", pos);
4983            return false;
4984          }
4985
4986          udist->addfloat(ind, (float)PyFloat_AsDouble(flt));
4987          Py_DECREF(flt);
4988        }
4989
4990        return WrapOrange(cont);
4991      }
4992
4993      else if (PyOrDistribution_Check(args)) {
4994        Py_INCREF(args);
4995        return args;
4996      }
4997
4998      else if (PyOrFloatVariable_Check(args))
4999        return WrapNewOrange(mlnew TContDistribution(PyOrange_AsVariable(args)), type);
5000    }
5001
5002    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
5003
5004  }
5005  PyCATCH;
5006}
5007
5008
5009PyObject *ContDistribution__reduce__(PyObject *self)
5010{
5011  PyTRY
5012    TContDistribution *cont = getContDistribution(self);
5013    TCharBuffer buf(sizeof(float) * 2 * (cont->size()  +  5));
5014
5015    buf.writeInt(cont->size());
5016    PITERATE(TContDistribution, ci, cont) {
5017      buf.writeFloat((*ci).first);
5018      buf.writeFloat((*ci).second);
5019    }
5020
5021    buf.writeFloat(cont->sum);
5022    buf.writeFloat(cont->sum2);
5023
5024    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderContDistribution"),
5025                                    self->ob_type,
5026                                    buf.buf, buf.length(),
5027                                    packOrangeDictionary(self));
5028  PyCATCH
5029}
5030
5031
5032PyObject *__pickleLoaderContDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
5033{
5034  PyTRY
5035    PyTypeObject *type;
5036    char *pbuf;
5037    int bufSize;
5038    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &pbuf, &bufSize))
5039      return PYNULL;
5040
5041    TContDistribution *cdi = new TContDistribution();
5042
5043    TCharBuffer buf(pbuf);
5044    for(int size = buf.readInt(); size--; ) {
5045      // cannot call buf.readFloat() in the make_pair call since we're not sure about the
5046      // order in which the arguments are evaluated
5047      const float p1 = buf.readFloat();
5048      const float p2 = buf.readFloat();
5049      cdi->insert(cdi->end(), make_pair(p1, p2));
5050    }
5051
5052    cdi->sum = buf.readFloat();
5053    cdi->sum2 = buf.readFloat();
5054
5055    return WrapNewOrange(cdi, type);
5056  PyCATCH
5057}
5058
5059
5060Py_ssize_t ContDistribution_len(PyObject *self)
5061{ PyTRY
5062    TContDistribution *cont = getContDistribution(self);
5063    return cont ? cont->size() : -1;
5064  PyCATCH_1
5065}
5066
5067
5068PyObject *ContDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
5069{ PyTRY
5070    TContDistribution *cont = getContDistribution(self);
5071    if (!cont)
5072      return PYNULL;
5073
5074    PyObject *nl=PyList_New(cont->size());
5075    Py_ssize_t i=0;
5076    PITERATE(TContDistribution, ci, cont)
5077      PyList_SetItem(nl, i++, PyFloat_FromDouble((double)(*ci).first));
5078    return nl;
5079  PyCATCH
5080}
5081
5082
5083PyObject *ContDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
5084{ PyTRY
5085    TContDistribution *cont = getContDistribution(self);
5086    if (!cont)
5087      return PYNULL;
5088
5089    PyObject *nl=PyList_New(cont->size());
5090    Py_ssize_t i=0;
5091    PITERATE(TContDistribution, ci, cont)
5092      PyList_SetItem(nl, i++, Py_BuildValue("ff", (*ci).first, (*ci).second));
5093    return nl;
5094  PyCATCH
5095}
5096
5097
5098PyObject *ContDistribution_values(PyObject *self) PYARGS(0, "() -> list")
5099{ PyTRY
5100    TContDistribution *cont = getContDistribution(self);
5101    if (!cont)
5102      return PYNULL;
5103
5104    PyObject *nl = PyList_New(cont->size());
5105    Py_ssize_t i = 0;
5106    const_PITERATE(TContDistribution, ci, cont)
5107      PyList_SetItem(nl, i++, PyFloat_FromDouble((*ci).second));
5108    return nl;
5109  PyCATCH
5110}
5111
5112
5113PyObject *ContDistribution_percentile(PyObject *self, PyObject *arg) PYARGS(METH_VARARGS, "(int) -> float")
5114{ PyTRY
5115    TContDistribution *cont = getContDistribution(self);
5116    if (!cont)
5117      return PYNULL;
5118
5119    float perc;
5120    if (!PyArg_ParseTuple(arg, "f:ContDistribution.percentile", &perc))
5121      return PYNULL;
5122
5123    return PyFloat_FromDouble(cont->percentile(perc));
5124  PyCATCH
5125}
5126
5127
5128PyObject *ContDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5129{ PyTRY
5130    CAST_TO(TContDistribution, dist)
5131
5132    PyObject *index;
5133    float weight = 1.0;
5134    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5135      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5136
5137    float f;
5138    if (PyNumber_ToFloat(index, f)) {
5139      dist->addfloat(f);
5140      RETURN_NONE;
5141    }
5142
5143    TValue val;
5144    if (!convertFromPython(index, val, dist->variable))
5145      PYERROR(PyExc_TypeError, "ContDistriubtion.add: invalid arguments", PYNULL);
5146
5147    dist->add(val, weight);
5148    RETURN_NONE;
5149  PyCATCH;
5150}
5151
5152
5153PyObject *ContDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5154{ PyTRY
5155    TContDistribution *cont = getContDistribution(self);
5156    if (!cont)
5157      return PYNULL;
5158
5159    return PyFloat_FromDouble(cont->error());
5160  PyCATCH
5161}
5162
5163
5164PyObject *ContDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5165{ PyTRY
5166    TContDistribution *cont = getContDistribution(self);
5167    if (!cont)
5168      return PYNULL;
5169
5170    return PyFloat_FromDouble(cont->average());
5171  PyCATCH
5172}
5173
5174
5175PyObject *ContDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5176{ PyTRY
5177    TContDistribution *cont = getContDistribution(self);
5178    if (!cont)
5179      return PYNULL;
5180
5181    return PyFloat_FromDouble(cont->dev());
5182  PyCATCH
5183}
5184
5185
5186PyObject *ContDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5187{ PyTRY
5188    TContDistribution *cont = getContDistribution(self);
5189    if (!cont)
5190      return PYNULL;
5191
5192    return PyFloat_FromDouble(cont->var());
5193  PyCATCH
5194}
5195
5196
5197PyObject *ContDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5198{ PyTRY
5199    TContDistribution *cont = getContDistribution(self);
5200    float x;
5201    if (!cont || !PyArg_ParseTuple(args, "f:ContDistribution.density", &x))
5202      return PYNULL;
5203
5204    return PyFloat_FromDouble(cont->p(x));
5205  PyCATCH
5206}
5207
5208
5209PyObject *GaussianDistribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Gaussian, "(mean, sigma) | (distribution) | () -> distribution") ALLOWS_EMPTY
5210{ PyTRY
5211    float mean = 0.0, sigma = 1.0;
5212
5213    if (PyArg_ParseTuple(args, "|ff", &mean, &sigma))
5214      return WrapNewOrange(mlnew TGaussianDistribution(mean, sigma), type);
5215
5216    PyErr_Clear();
5217
5218    PDistribution dist;
5219    if (PyArg_ParseTuple(args, "O&", &cc_Distribution, &dist))
5220      return WrapNewOrange(mlnew TGaussianDistribution(dist), type);
5221
5222    PYERROR(PyExc_TypeError, "GaussianDistribution expects mean and sigma, or distribution or nothing", PYNULL)
5223
5224  PyCATCH
5225}
5226
5227
5228PyObject *GaussianDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5229{ PyTRY
5230    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).average());
5231  PyCATCH
5232}
5233
5234
5235PyObject *GaussianDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5236{ PyTRY
5237    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).error());
5238  PyCATCH
5239}
5240
5241
5242PyObject *GaussianDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5243{ PyTRY
5244    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).dev());
5245  PyCATCH
5246}
5247
5248
5249PyObject *GaussianDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5250{ PyTRY
5251    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).var());
5252  PyCATCH
5253}
5254
5255
5256PyObject *GaussianDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5257{ PyTRY
5258    float x;
5259    if (!PyArg_ParseTuple(args, "f:GaussianDistribution.density", &x))
5260      return PYNULL;
5261
5262    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).p(x));
5263  PyCATCH
5264}
5265
5266
5267/* We redefine new (removed from below!) and add mapping methods
5268*/
5269
5270PyObject *getClassDistribution(PyObject *type, PyObject *args) PYARGS(METH_VARARGS, "(examples[, weightID]) -> Distribution")
5271{ PyTRY
5272    int weightID;
5273    PExampleGenerator gen = exampleGenFromArgs(args, weightID);
5274    if (!gen)
5275      return PYNULL;
5276    return WrapOrange(getClassDistribution(gen, weightID));
5277  PyCATCH
5278}
5279
5280
5281/* modified new (defined below), modified getitem, setitem */
5282
5283PDomainDistributions PDomainDistributions_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5284PyObject *DomainDistributions_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5285PyObject *DomainDistributions_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5286int       DomainDistributions_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_setslice(self, start, stop, item); }
5287PyObject *DomainDistributions_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5288int       DomainDistributions_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5289Py_ssize_t       DomainDistributions_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_len(self); }
5290PyObject *DomainDistributions_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5291PyObject *DomainDistributions_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5292PyObject *DomainDistributions_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5293PyObject *DomainDistributions_str(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5294PyObject *DomainDistributions_repr(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5295int       DomainDistributions_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5296PyObject *DomainDistributions_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5297PyObject *DomainDistributions_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5298PyObject *DomainDistributions_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5299PyObject *DomainDistributions_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DomainDistributions") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5300PyObject *DomainDistributions_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5301PyObject *DomainDistributions_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5302PyObject *DomainDistributions_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_native(self); }
5303PyObject *DomainDistributions_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5304PyObject *DomainDistributions_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5305PyObject *DomainDistributions_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5306PyObject *DomainDistributions_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5307PyObject *DomainDistributions__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5308
5309
5310/* Note that this is not like callable-constructors. They return different type when given
5311   parameters, while this one returns the same type, disregarding whether it was given examples or not.
5312*/
5313PyObject *DomainDistributions_new(PyTypeObject *type, PyObject *args, PyObject *keywds) BASED_ON(Orange - Orange.statistics.distribution.Domain, "(examples[, weightID, skipDiscrete, skipContinuous] | <list of Distribution>) -> DomainDistributions") ALLOWS_EMPTY
5314{ PyTRY
5315    if (!args || !PyTuple_Size(args))
5316      return WrapNewOrange(mlnew TDomainDistributions(), type);
5317
5318    int weightID = 0;
5319    PExampleGenerator gen;
5320    int skipDiscrete=0, skipContinuous=0;
5321    if (PyArg_ParseTuple(args, "O&|O&ii:Distribution.new", &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID, &skipDiscrete, &skipContinuous))
5322      return WrapNewOrange(mlnew TDomainDistributions(gen, weightID, skipDiscrete!=0, skipContinuous!=0), type);
5323
5324    PyErr_Clear();
5325
5326    PyObject *obj = ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_new(type, args, keywds);
5327    if (obj)
5328      if (obj!=Py_None)
5329        return obj;
5330      else
5331        Py_DECREF(obj);
5332
5333    PyErr_Clear();
5334    PYERROR(PyExc_TypeError, "DomainDistributions.__init__ expect examples or a list of Distributions", PYNULL);
5335
5336  PyCATCH
5337}
5338
5339
5340/* We keep the sequence methods and add mapping interface */
5341
5342int DomainDistributions_getItemIndex(PyObject *self, PyObject *args)
5343{ CAST_TO_err(TDomainDistributions, bas, -1);
5344
5345  if (PyInt_Check(args)) {
5346    int i=(int)PyInt_AsLong(args);
5347    if ((i>=0) && (i<int(bas->size())))
5348      return i;
5349    else
5350      PYERROR(PyExc_IndexError, "index out of range", -1);
5351  }
5352
5353  if (PyString_Check(args)) {
5354    char *s=PyString_AsString(args);
5355    PITERATE(TDomainDistributions, ci, bas)
5356      if ((*ci)->variable && ((*ci)->variable->get_name()==s))
5357        return ci - bas->begin();
5358
5359    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", s);
5360    return -1;
5361  }
5362
5363  if (PyOrVariable_Check(args)) {
5364    PVariable var = PyOrange_AsVariable(args);
5365    PITERATE(TDomainDistributions, ci, bas)
5366      if ((*ci)->variable && ((*ci)->variable==var))
5367        return ci - bas->begin();
5368
5369    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", var->get_name().length() ? var->get_name().c_str() : "<no name>");
5370    return -1;
5371  }
5372
5373  PYERROR(PyExc_IndexError, "invalid index type", -1);
5374}
5375
5376
5377PyObject *DomainDistributions_getitem(PyObject *self, PyObject *args)
5378{ PyTRY
5379    int index=DomainDistributions_getItemIndex(self, args);
5380    if (index<0)
5381      return PYNULL;
5382    return WrapOrange(POrange(SELF_AS(TDomainDistributions).at(index)));
5383  PyCATCH
5384}
5385
5386
5387int DomainDistributions_setitem(PyObject *self, PyObject *args, PyObject *obj)
5388{ PyTRY
5389    PDistribution bas;
5390
5391    if (!PyOrBasicAttrStat_Check(obj))
5392      PYERROR(PyExc_TypeError, "invalid Distribution object", -1);
5393
5394    int index=DomainDistributions_getItemIndex(self, args);
5395    if (index==-1)
5396      return -1;
5397
5398    SELF_AS(TDomainDistributions)[index] = PyOrange_AsDistribution(obj);
5399    return 0;
5400  PyCATCH_1
5401}
5402
5403
5404PDistributionList PDistributionList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5405PyObject *DistributionList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5406PyObject *DistributionList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange, "(<list of Distribution>)") ALLOWS_EMPTY { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_new(type, arg, kwds); }
5407PyObject *DistributionList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5408int       DistributionList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5409PyObject *DistributionList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5410int       DistributionList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_setslice(self, start, stop, item); }
5411Py_ssize_t       DistributionList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_len(self); }
5412PyObject *DistributionList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5413PyObject *DistributionList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5414PyObject *DistributionList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5415PyObject *DistributionList_str(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5416PyObject *DistributionList_repr(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5417int       DistributionList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5418PyObject *DistributionList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5419PyObject *DistributionList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5420PyObject *DistributionList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5421PyObject *DistributionList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DistributionList") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5422PyObject *DistributionList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5423PyObject *DistributionList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5424PyObject *DistributionList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_native(self); }
5425PyObject *DistributionList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5426PyObject *DistributionList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5427PyObject *DistributionList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5428PyObject *DistributionList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5429PyObject *DistributionList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5430
5431
5432
5433/* ************ LEARNER ************ */
5434
5435#include "classify.hpp"
5436#include "learn.hpp"
5437
5438BASED_ON(EFMDataDescription, Orange)
5439
5440PyObject *EFMDataDescription__reduce__(PyObject *self)
5441{
5442  CAST_TO(TEFMDataDescription, edd);
5443
5444  TCharBuffer buf(0);
5445  buf.writeFloatVector(edd->averages);
5446  buf.writeFloatVector(edd->matchProbabilities);
5447  buf.writeInt(edd->originalWeight);
5448  buf.writeInt(edd->missingWeight);
5449
5450  return Py_BuildValue("O(OOs#)N", getExportedFunction("__pickleLoaderEFMDataDescription"),
5451                                  WrapOrange(edd->domain),
5452                                  WrapOrange(edd->domainDistributions),
5453                                  buf.buf, buf.length(),
5454                                  packOrangeDictionary(self));
5455}
5456
5457
5458PyObject *__pickleLoaderEFMDataDescription(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(domain, domainDistributions, packed_data)")
5459{
5460  PDomain domain;
5461  PDomainDistributions domainDistributions;
5462  char *pbuf;
5463  int bufSize;
5464
5465  if (!PyArg_ParseTuple(args, "O&O&s#", ccn_Domain, &domain, ccn_DomainDistributions, &domainDistributions, &pbuf, &bufSize))
5466    return PYNULL;
5467
5468  TEFMDataDescription *edd = new TEFMDataDescription(domain, domainDistributions);
5469  PEFMDataDescription wedd = edd;
5470
5471  TCharBuffer buf(pbuf);
5472  buf.readFloatVector(edd->averages);
5473  buf.readFloatVector(edd->matchProbabilities);
5474  edd->originalWeight = buf.readInt();
5475  edd->missingWeight = buf.readInt();
5476
5477  return WrapOrange(wedd);
5478}
5479
5480
5481ABSTRACT(LearnerFD - Orange.classification.LearnerFD, Learner)
5482
5483PyObject *Learner_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.classification.Learner, "<abstract>")
5484{ if (type == (PyTypeObject *)&PyOrLearner_Type)
5485    return setCallbackFunction(WrapNewOrange(mlnew TLearner_Python(), type), args);
5486  else
5487    return WrapNewOrange(mlnew TLearner_Python(), type);
5488}
5489
5490
5491PyObject *Learner__reduce__(PyObject *self)
5492{
5493  return callbackReduce(self, PyOrLearner_Type);
5494}
5495
5496
5497PyObject *Learner_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(examples) -> Classifier")
5498{
5499  PyTRY
5500    NO_KEYWORDS
5501
5502    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrLearner_Type) {
5503      PyErr_Format(PyExc_SystemError, "Learner.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
5504      return PYNULL;
5505    }
5506
5507    PExampleGenerator egen;
5508    int weight = 0;
5509    if (!PyArg_ParseTuple(targs, "O&|O&", pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weight))
5510      PYERROR(PyExc_AttributeError, "Learner.__call__: examples and, optionally, weight attribute expected", PYNULL);
5511
5512    // Here for compatibility with obsolete scripts
5513/*    if (PyTuple_Size(targs)==1) {
5514      if (((TPyOrange *)self)->orange_dict) {
5515        PyObject *pyweight = PyDict_GetItemString(((TPyOrange *)self)->orange_dict, "weight");
5516        if (pyweight && PyInt_Check(pyweight))
5517          weight = (int)PyInt_AsLong(pyweight);
5518      }
5519    }
5520*/
5521    PClassifier classfr = SELF_AS(TLearner)(egen, weight);
5522    if (!classfr)
5523      PYERROR(PyExc_SystemError, "learning failed", PYNULL);
5524
5525    return WrapOrange(classfr);
5526  PyCATCH
5527}
5528
5529
5530
5531
5532/* ************ CLASSIFIERS ************ */
5533
5534#include "classify.hpp"
5535#include "majority.hpp"
5536
5537ABSTRACT(ClassifierFD - Orange.classification.ClassifierFD, Classifier)
5538
5539PyObject *DefaultClassifier_new(PyTypeObject *tpe, PyObject *args, PyObject *kw) BASED_ON(Classifier - Orange.classification.ConstantClassifier, "([defaultVal])") ALLOWS_EMPTY
5540{
5541  PyObject *arg1 = NULL, *arg2 = NULL;
5542  if (!PyArg_UnpackTuple(args, "DefaultClassifier.__new__", 0, 2, &arg1, &arg2))
5543    return PYNULL;
5544
5545  if (!arg1)
5546    return WrapNewOrange(mlnew TDefaultClassifier(), tpe);
5547
5548  if (!arg2) {
5549    if (PyOrVariable_Check(arg1))
5550      return WrapNewOrange(mlnew TDefaultClassifier(PyOrange_AsVariable(arg1)), tpe);
5551    TValue val;
5552    if (convertFromPython(arg1, val)) {
5553      PVariable var = PyOrValue_Check(arg1) ? PyValue_AS_Variable(arg1) : PVariable();
5554      return WrapNewOrange(mlnew TDefaultClassifier(var, val, PDistribution()), tpe);
5555    }
5556  }
5557
5558  else
5559    if (PyOrVariable_Check(arg1)) {
5560      PVariable classVar = PyOrange_AsVariable(arg1);
5561      TValue val;
5562      if (convertFromPython(arg2, val, classVar))
5563        return WrapNewOrange(mlnew TDefaultClassifier(classVar, val, PDistribution()), tpe);
5564    }
5565
5566  PYERROR(PyExc_TypeError, "DefaultClassifier's constructor expects a Variable, a Value or both", PYNULL);
5567}
5568
5569C_NAMED(RandomLearner - Orange.classification.RandomLearner, Learner, "([probabilities=])")
5570C_NAMED(RandomClassifier - Orange.classification.RandomClassifier, Classifier, "([probabilities=])")
5571
5572PClassifierList PClassifierList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::P_FromArguments(arg); }
5573PyObject *ClassifierList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_FromArguments(type, arg); }
5574PyObject *ClassifierList_new(PyTypeObject *type, PyObject *arg, PyObject *kwds) BASED_ON(Orange - Orange.classification.ClassifierList, "(<list of Classifier>)")  ALLOWS_EMPTY { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_new(type, arg, kwds); }
5575PyObject *ClassifierList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_getitem(self, index); }
5576int       ClassifierList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_setitem(self, index, item); }
5577PyObject *ClassifierList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_getslice(self, start, stop); }
5578int       ClassifierList_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *item) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_setslice(self, start, stop, item); }
5579Py_ssize_t       ClassifierList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_len(self); }
5580PyObject *ClassifierList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_richcmp(self, object, op); }
5581PyObject *ClassifierList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_concat(self, obj); }
5582PyObject *ClassifierList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_repeat(self, times); }
5583PyObject *ClassifierList_str(TPyOrange *self) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_str(self); }
5584PyObject *ClassifierList_repr(TPyOrange *self) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_str(self); }
5585int       ClassifierList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_contains(self, obj); }
5586PyObject *ClassifierList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Classifier) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_append(self, item); }
5587PyObject *ClassifierList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_extend(self, obj); }
5588PyObject *ClassifierList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Classifier) -> int") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_count(self, obj); }
5589PyObject *ClassifierList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ClassifierList") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_filter(self, args); }
5590PyObject *ClassifierList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Classifier) -> int") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_index(self, obj); }
5591PyObject *ClassifierList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_insert(self, args); }
5592PyObject *ClassifierList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_native(self); }
5593PyObject *ClassifierList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Classifier") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_pop(self, args); }
5594PyObject *ClassifierList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Classifier) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_remove(self, obj); }
5595PyObject *ClassifierList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_reverse(self); }
5596PyObject *ClassifierList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_sort(self, args); }
5597PyObject *ClassifierList__reduce__(TPyOrange *self, PyObject *) {