source: orange/source/orange/lib_kernel.cpp @ 10593:4e2c1f5ede07

Revision 10593:4e2c1f5ede07, 210.0 KB checked in by Janez Demšar <janez.demsar@…>, 2 years ago (diff)

When calling to_numpy("c") on a classless domain, it now returns an empty numpy array of size
(no_of_examples, 0).

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