source: orange/source/orange/lib_kernel.cpp @ 9532:2c6a8bb6ec89

Revision 9532:2c6a8bb6ec89, 207.2 KB checked in by janezd <janez.demsar@…>, 2 years ago (diff)

Conversion to numpy now supports multiple classes (Ticket #1012)

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