source: orange/source/orange/lib_kernel.cpp @ 11705:f70144877d24

Revision 11705:f70144877d24, 213.0 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Prevent the 'attributes' from being deleted.

Line 
1#ifdef _MSC_VER
2  #pragma warning (disable : 4786 4114 4018 4267 4244)
3#endif
4
5#include "vars.hpp"
6#include "domain.hpp"
7#include "examplegen.hpp"
8#include "table.hpp"
9#include "learn.hpp"
10#include "estimateprob.hpp"
11#include "preprocessors.hpp"
12#include "callback.hpp"
13
14#include "cls_value.hpp"
15#include "cls_example.hpp"
16#include "lib_kernel.hpp"
17#include "vectortemplates.hpp"
18
19
20#include "externs.px"
21
22#include "converts.hpp"
23#include "cls_orange.hpp"
24#include "slist.hpp"
25
26WRAPPER(ExampleTable);
27
28PStringList PStringList_FromArguments(PyObject *arg);
29
30/* This was moved from lib_vectors.cpp:
31    - nobody used it
32    - lib_vectors.cpp is automatically generated and I'd hate to add this as an exception
33
34int pt_FloatList(PyObject *args, void *floatlist)
35{
36  *(PFloatList *)(floatlist) = PFloatList_FromArguments(args);
37  return PyErr_Occurred() ? -1 : 0;
38}
39*/
40
41
42int pt_StringList(PyObject *args, void *stringList)
43{
44  PStringList &rsl = *(PStringList *)stringList;
45
46  if (PyOrStringList_Check(args))
47    rsl = PyOrange_AsStringList(args);
48  else
49    rsl = PStringList_FromArguments(args);
50
51  return rsl ? 1 : 0;
52}
53
54int ptn_StringList(PyObject *args, void *stringList)
55{
56  if (args == Py_None) {
57    *(PStringList *)stringList = PStringList();
58    return 1;
59  }
60
61  return pt_StringList(args, stringList);
62}
63
64
65/* ************ PROGRESS CALLBACK ************ */
66
67#include "progress.hpp"
68
69PyObject *ProgressCallback_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
70{ if (type == (PyTypeObject *)&PyOrProgressCallback_Type)
71    return setCallbackFunction(WrapNewOrange(mlnew TProgressCallback_Python(), type), args);
72  else
73    return WrapNewOrange(mlnew TProgressCallback_Python(), type);
74}
75
76
77PyObject *ProgressCallback__reduce__(PyObject *self)
78{
79  return callbackReduce(self, PyOrProgressCallback_Type);
80}
81
82
83PyObject *ProgressCallback_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(float[, Orange]) -> bool")
84{
85  PyTRY
86    NO_KEYWORDS
87
88    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrProgressCallback_Type) {
89      PyErr_Format(PyExc_SystemError, "ProgressCallback.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
90      return PYNULL;
91    }
92
93    float f;
94    POrange o;
95    if (!PyArg_ParseTuple(targs, "f|O&:ProgressCallback", &f, ccn_Orange, &o))
96      return PYNULL;
97
98    return PyInt_FromLong(SELF_AS(TProgressCallback)(f, o) ? 1 : 0);
99  PyCATCH
100}
101
102/* ************ VARIABLE ************ */
103
104PVarList PVarList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::P_FromArguments(arg); }
105PyObject *VarList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_FromArguments(type, arg); }
106PyObject *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); }
107PyObject *VarList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_getitem(self, index); }
108int       VarList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_setitem(self, index, item); }
109PyObject *VarList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_getslice(self, start, stop); }
110int       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); }
111Py_ssize_t       VarList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_len(self); }
112PyObject *VarList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_richcmp(self, object, op); }
113PyObject *VarList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_concat(self, obj); }
114PyObject *VarList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_repeat(self, times); }
115PyObject *VarList_str(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_str(self); }
116PyObject *VarList_repr(TPyOrange *self) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_str(self); }
117int       VarList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_contains(self, obj); }
118PyObject *VarList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Variable) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_append(self, item); }
119PyObject *VarList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_extend(self, obj); }
120PyObject *VarList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> int") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_count(self, obj); }
121PyObject *VarList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> VarList") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_filter(self, args); }
122PyObject *VarList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> int") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_index(self, obj); }
123PyObject *VarList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_insert(self, args); }
124PyObject *VarList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_native(self); }
125PyObject *VarList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Variable") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_pop(self, args); }
126PyObject *VarList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_remove(self, obj); }
127PyObject *VarList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_reverse(self); }
128PyObject *VarList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_sort(self, args); }
129PyObject *VarList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PVarList, TVarList, PVariable, &PyOrVariable_Type>::_reduce(self); }
130
131
132PVarListList PVarListList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::P_FromArguments(arg); }
133PyObject *VarListList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_FromArguments(type, arg); }
134PyObject *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); }
135PyObject *VarListList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_getitem(self, index); }
136int       VarListList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_setitem(self, index, item); }
137PyObject *VarListList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_getslice(self, start, stop); }
138int       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); }
139Py_ssize_t       VarListList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_len(self); }
140PyObject *VarListList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_richcmp(self, object, op); }
141PyObject *VarListList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_concat(self, obj); }
142PyObject *VarListList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_repeat(self, times); }
143PyObject *VarListList_str(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_str(self); }
144PyObject *VarListList_repr(TPyOrange *self) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_str(self); }
145int       VarListList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_contains(self, obj); }
146PyObject *VarListList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(VarList) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_append(self, item); }
147PyObject *VarListList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_extend(self, obj); }
148PyObject *VarListList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> int") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_count(self, obj); }
149PyObject *VarListList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> VarListList") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_filter(self, args); }
150PyObject *VarListList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> int") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_index(self, obj); }
151PyObject *VarListList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_insert(self, args); }
152PyObject *VarListList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_native(self); }
153PyObject *VarListList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> VarList") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_pop(self, args); }
154PyObject *VarListList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(VarList) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_remove(self, obj); }
155PyObject *VarListList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_reverse(self); }
156PyObject *VarListList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_sort(self, args); }
157PyObject *VarListList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PVarListList, TVarListList, PVarList, &PyOrVarList_Type>::_reduce(self); }
158
159
160PVarList knownVars(PyObject *keywords)
161{
162  PVarList variables;
163  PyObject *pyknownVars=keywords ? PyDict_GetItemString(keywords, "use") : PYNULL;
164  if (!pyknownVars || (pyknownVars == Py_None))
165    return PVarList();
166
167  if (PyOrVarList_Check(pyknownVars))
168    variables = ((GCPtr<TVarList>)(PyOrange_AS_Orange(pyknownVars)));
169
170  else if (PyOrDomain_Check(pyknownVars)) {
171    PDomain domain = PyOrange_AsDomain(pyknownVars);
172    variables = mlnew TVarList(domain->variables.getReference());
173    ITERATE(TMetaVector, mi, domain->metas)
174      variables->push_back((*mi).variable);
175  }
176
177  else
178    variables= PVarList_FromArguments(pyknownVars);
179
180  if (!variables)
181    raiseError("invalid value for 'use' argument"); // PYERROR won't do - NULL is a valid value to return...
182
183  return variables;
184}
185
186
187PDomain knownDomain(PyObject *keywords)
188{
189  PVarList variables;
190  PyObject *pyknownDomain = keywords ? PyDict_GetItemString(keywords, "domain") : PYNULL;
191  if (!pyknownDomain || (pyknownDomain == Py_None))
192    return PDomain();
193
194  if (!PyOrDomain_Check(pyknownDomain))
195    raiseError("invalid value for 'domain' argument"); // PYERROR won't do - NULL is a valid value to return...
196
197  return PyOrange_AsDomain(pyknownDomain);
198}
199
200
201TMetaVector *knownMetas(PyObject *keywords)
202{
203  if (!keywords)
204    return NULL;
205
206  PyObject *pyknownDomain = PyDict_GetItemString(keywords, "domain");
207  if (pyknownDomain && (pyknownDomain != Py_None)) {
208    if (!PyOrDomain_Check(pyknownDomain))
209      raiseError("invalid value for 'domain' argument"); // PYERROR won't do - NULL is a valid value to return...
210    return &PyOrange_AsDomain(pyknownDomain)->metas;
211  }
212
213  pyknownDomain = PyDict_GetItemString(keywords, "use");
214  if (pyknownDomain && PyOrDomain_Check(pyknownDomain))
215    return &PyOrange_AsDomain(pyknownDomain)->metas;
216
217  return NULL;
218}
219
220ABSTRACT(Variable - Orange.feature.Descriptor, Orange)
221C_NAMED(EnumVariable - Orange.feature.Discrete, Variable, "([name=, values=, autoValues=, distributed=, getValueFrom=])")
222C_NAMED(FloatVariable - Orange.feature.Continuous, Variable, "([name=, startValue=, endValue=, stepValue=, distributed=, getValueFrom=])")
223
224PyObject *PyVariable_MakeStatus_FromLong(long ok);
225
226/* Left for compatibility (also put into the header, as for others */
227PyObject *MakeStatus()
228{ PyObject *mt=PyModule_New("MakeStatus");
229  PyModule_AddObject(mt, "OK", PyVariable_MakeStatus_FromLong((long)TVariable::OK));
230  PyModule_AddObject(mt, "MissingValues", PyVariable_MakeStatus_FromLong((long)TVariable::MissingValues));
231  PyModule_AddObject(mt, "NoRecognizedValues", PyVariable_MakeStatus_FromLong((long)TVariable::NoRecognizedValues));
232  PyModule_AddObject(mt, "Incompatible", PyVariable_MakeStatus_FromLong((long)TVariable::Incompatible));
233  PyModule_AddObject(mt, "NotFound", PyVariable_MakeStatus_FromLong((long)TVariable::NotFound));
234  return mt;
235}
236
237PYCLASSCONSTANT(Variable, MakeStatus, MakeStatus())
238
239
240PyObject *Variable_getExisting(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, failOn]]) -> (Variable|None, status)")
241{
242  PyTRY
243    char *varName;
244    int varType;
245    PStringList values;
246    PStringList unorderedValues_asList;
247    int failOn = TVariable::Incompatible;
248
249    if (!PyArg_ParseTuple(args, "si|O&O&i:Variable.getExisting", &varName, &varType, ptn_StringList, &values, ptn_StringList, &unorderedValues_asList, &failOn))
250      return NULL;
251
252    set<string> unorderedValues;
253    if (unorderedValues_asList)
254      unorderedValues.insert(unorderedValues_asList->begin(), unorderedValues_asList->end());
255
256    int status;
257    PVariable var = TVariable::getExisting(varName, varType, values.getUnwrappedPtr(), &unorderedValues, failOn, &status);
258    return Py_BuildValue("NN", WrapOrange(var), PyVariable_MakeStatus_FromLong(status));
259  PyCATCH
260}
261
262
263PyObject *Variable_retrieve(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, failOn]]) -> (Variable|None, status)")
264{
265    return Variable_getExisting(NULL, args);
266}
267
268
269PyObject *newmetaid(PyObject *, PyObject *args);
270
271PyObject *Variable_new_meta_id(PyObject *, PyObject *args)  PYARGS(METH_VARARGS | METH_STATIC, "([Variable]) -> int")
272{
273    return newmetaid(NULL, args);
274}
275
276PyObject *Variable_make(PyObject *, PyObject *args) PYARGS(METH_VARARGS | METH_STATIC, "(name, type[, fixedOrderValues[, otherValues, createNewOn]]) -> (Variable|None, status)")
277{
278  PyTRY
279    char *varName;
280    int varType;
281    PStringList values;
282    PStringList unorderedValues_asList;
283    int createNewOn = TVariable::Incompatible;
284
285    if (!PyArg_ParseTuple(args, "si|O&O&i:Variable.make", &varName, &varType, ptn_StringList, &values, ptn_StringList, &unorderedValues_asList, &createNewOn))
286      return NULL;
287
288    set<string> unorderedValues;
289    if (unorderedValues_asList)
290      unorderedValues.insert(unorderedValues_asList->begin(), unorderedValues_asList->end());
291
292    int status;
293    PVariable var = TVariable::make(varName, varType, values.getUnwrappedPtr(), &unorderedValues, createNewOn, &status);
294    return Py_BuildValue("NN", WrapOrange(var), PyVariable_MakeStatus_FromLong(status));
295  PyCATCH
296}
297
298//set and get name
299int Variable_set_name(PyObject *self, PyObject *name)
300{ 
301    char *varName;
302    if (!PyString_Check(name))
303        PYERROR(PyExc_AttributeError, "string expected", 0);
304    varName = PyString_AsString(name);
305    PVariable var = PyOrange_AsVariable(self);
306    var->set_name(string(varName));
307    return 0;
308}
309
310
311PyObject *Variable_get_name(PyObject *self) 
312{
313    PVariable var = PyOrange_AsVariable(self);
314    return Py_BuildValue("s", var->get_name().c_str());
315}
316
317
318/*
319 * Variable.attributes dictionary getter/setter
320 */
321
322PyObject *Variable_get_attributes(TPyOrange *self)
323{
324    PyObject *res = NULL;
325
326    if (self->orange_dict && (res = PyDict_GetItemString(self->orange_dict, "attributes"))) {
327        Py_INCREF(res);
328        return res;
329    }
330
331    PyObject *dict = PyDict_New();
332    Orange_setattrDictionary(self, "attributes", dict, false);
333    return dict;
334}
335
336
337int Variable_set_attributes(TPyOrange *self, PyObject *dict)
338{
339    if (!dict) {
340        PYERROR(PyExc_TypeError, "Cannot delete 'attributes' dict", 0);
341    }
342
343    if (!PyDict_Check(dict)) {
344        PYERROR(PyExc_TypeError, "'attributes' must be a dict", 0);
345    }
346    return Orange_setattrDictionary(self, "attributes", dict, false);
347}
348
349
350#include "stringvars.hpp"
351C_NAMED(StringVariable - Orange.feature.String, Variable, "([name=])")
352
353#include "pythonvars.hpp"
354C_NAMED(PythonVariable - Orange.feature.Python, Variable, "([name=])")
355
356PyObject *PythonValue_new(PyTypeObject *type, PyObject *args, PyObject *kwds) BASED_ON(SomeValue, "([object])")
357{
358  if (!PyTuple_Size(args))
359    return WrapNewOrange(mlnew TPythonValue(), type);
360
361  if (PyTuple_Size(args)==1)
362    return WrapNewOrange(mlnew TPythonValue(PyTuple_GET_ITEM(args, 0)), type);
363
364  else
365    PYERROR(PyExc_TypeError, "PythonValue.__init__ expects up to one Python object", PYNULL);
366}
367
368
369PyObject *PythonValueSpecial_new(PyTypeObject *type, PyObject *args, PyObject *kwds) BASED_ON(Orange, "(int)") ALLOWS_EMPTY
370{
371  int vtype = 1;
372  if (!PyArg_ParseTuple(args, "|i:PythonValueSpecial.__init__", &vtype))
373    return PYNULL;
374
375  return WrapNewOrange(mlnew TPythonValueSpecial(vtype), type);
376}
377
378
379int PythonValue_set_value(PyObject *self, PyObject *value)
380{
381  Py_INCREF(value);
382  SELF_AS(TPythonValue).value = value;
383  return 0;
384}
385
386
387PyObject *PythonValue_get_value(PyObject *self)
388{
389  PyObject *res = SELF_AS(TPythonValue).value;
390  Py_INCREF(res);
391  return res;
392}
393
394
395PyObject *PythonValue__reduce__(PyObject *self)
396{
397  return Py_BuildValue("O(O)", (PyObject *)(self->ob_type), SELF_AS(TPythonValue).value);
398}
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
1883class GlobalFiletypeDefinitionVector: public vector<TFiletypeDefinition>
1884{
1885public:
1886  ~GlobalFiletypeDefinitionVector()
1887  {
1888    /*
1889     * The 'filetypeDefinitions' below will be (and should be)
1890     * the only instance and it will outlive the Python interpreter.
1891     * This destructor will be called in clib's exit() and at that time the
1892     * 'saver' and 'loader' pointers in TFiletypeDefinition are no
1893     * longer valid so we set them to NULL so Py_XDECREF macro in
1894     * TFiletypeDefinition destructor does nothing.
1895     */
1896    for (GlobalFiletypeDefinitionVector::iterator iter = begin();
1897         iter != end();
1898         iter++)
1899    {
1900      iter->loader = NULL;
1901      iter->saver = NULL;
1902    }
1903  }
1904};
1905
1906GlobalFiletypeDefinitionVector filetypeDefinitions;
1907
1908
1909/* lower case to avoid any ambiguity problems (don't know how various compilers can react when
1910   registerFiletype is cast by the code produced by pyxtract */
1911ORANGE_API void registerFiletype(const char *name, const vector<string> &extensions, PyObject *loader, PyObject *saver)
1912{
1913  TFiletypeDefinition ftd(name, loader, saver);
1914  ftd.extensions = extensions;
1915  filetypeDefinitions.push_back(ftd);
1916}
1917
1918bool fileExists(const string &s);
1919const char *getExtension(const char *name);
1920
1921
1922vector<TFiletypeDefinition>::iterator findFiletypeByExtension(const char *name, bool needLoader, bool needSaver, bool exhaustive)
1923{
1924  const char *extension = getExtension(name);
1925
1926  if (extension) {
1927    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1928      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1929        ITERATE(TStringList, ei, (*fi).extensions)
1930          if (*ei == extension)
1931            return fi;
1932  }
1933
1934  else if (exhaustive) {
1935    ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions)
1936      if ((!needLoader || (*fi).loader) && (!needSaver || (*fi).saver))
1937        ITERATE(TStringList, ei, (*fi).extensions)
1938          if (fileExists(name + *ei))
1939            return fi;
1940  }
1941
1942  return filetypeDefinitions.end();
1943}
1944
1945
1946PyObject *registerFileType(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(name, extensions, loader, saver) -> None")
1947{
1948  char *name;
1949  PyObject *pyextensions, *loader, *saver;
1950  if (!PyArg_ParseTuple(args, "sOOO:registerFiletype", &name, &loader, &saver, &pyextensions))
1951    return PYNULL;
1952
1953  TFiletypeDefinition ftd(name, loader, saver);
1954
1955  if (PyString_Check(pyextensions))
1956    ftd.extensions.push_back(PyString_AsString(pyextensions));
1957  else {
1958    PStringList extensions = PStringList_FromArguments(pyextensions);
1959    if (!extensions)
1960      return PYNULL;
1961    ftd.extensions = extensions.getReference();
1962  }
1963
1964  vector<TFiletypeDefinition>::iterator fi(filetypeDefinitions.begin()), fe(filetypeDefinitions.begin());
1965  for(; (fi != fe) && ((*fi).name != name); fi++);
1966
1967  if (fi==fe)
1968    filetypeDefinitions.push_back(ftd);
1969  else
1970    *fi = ftd;
1971
1972  RETURN_NONE;
1973}
1974
1975
1976extern char *fileTypes[][2];
1977
1978PyObject *getRegisteredFileTypes(PyObject *, PyObject *, PyObject *) PYARGS(METH_NOARGS, "() -> ((extension, description, loader, saver), ...)")
1979{
1980  char *(*t)[2] = fileTypes;
1981  while(**t)
1982    t++;
1983
1984  int builtIns = t-fileTypes;
1985  int i = 0;
1986  PyObject *types = PyTuple_New(builtIns + filetypeDefinitions.size());
1987  for(t = fileTypes; **t; t++)
1988    PyTuple_SetItem(types, i++, Py_BuildValue("ss", (*t)[0], (*t)[1]));
1989
1990  ITERATE(vector<TFiletypeDefinition>, fi, filetypeDefinitions) {
1991    string exts;
1992    ITERATE(TStringList, ei, (*fi).extensions)
1993      exts += (exts.size() ? " *" : "*") + *ei;
1994
1995    PyObject *ploader = (*fi).loader, *psaver = (*fi).saver;
1996    if (!ploader) {
1997      ploader = Py_None;
1998      Py_INCREF(Py_None);
1999    }
2000    if (!psaver) {
2001      psaver = Py_None;
2002      Py_INCREF(Py_None);
2003    }
2004    PyTuple_SetItem(types, i++, Py_BuildValue("ssOO", (*fi).name.c_str(), exts.c_str(), ploader, psaver));
2005  }
2006
2007  return types;
2008}
2009
2010#include "examplegen.hpp"
2011#include "table.hpp"
2012#include "filter.hpp"
2013
2014
2015PyObject *loadDataByPython(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool exhaustiveFilesearch, bool &fileFound)
2016{
2017  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, true, false, exhaustiveFilesearch);
2018  fileFound = fi!=filetypeDefinitions.end();
2019
2020  if (!fileFound)
2021    return PYNULL;
2022
2023  PyObject *res = PyObject_Call((*fi).loader, argstuple, keywords);
2024  if (!res)
2025    throw pyexception();
2026  if (res == Py_None)
2027    return res;
2028
2029  bool gotTuple = PyTuple_Check(res);
2030  PyObject *res1 = gotTuple ? PyTuple_GET_ITEM(res, 0) : res;
2031
2032  if (PyOrExampleTable_Check(res1))
2033    return res;
2034
2035  PExampleGenerator gen;
2036  if (!exampleGenFromParsedArgs(res1, gen)) {
2037    Py_DECREF(res);
2038    return PYNULL;
2039  }
2040
2041  TExampleTable *table = gen.AS(TExampleTable);
2042  if (!table) {
2043    Py_DECREF(res);
2044    return PYNULL;
2045  }
2046
2047  if (gotTuple) {
2048    PyObject *nres = PyTuple_New(PyTuple_Size(res));
2049    PyTuple_SetItem(nres, 0, WrapNewOrange(table, type));
2050    for(Py_ssize_t i = 1; i < PyTuple_Size(res); i++)
2051      PyTuple_SetItem(nres, i, PyTuple_GET_ITEM(res, i));
2052
2053    Py_DECREF(res);
2054    return nres;
2055  }
2056  else {
2057    Py_DECREF(res);
2058    return WrapNewOrange(table, type);
2059  }
2060}
2061
2062bool readUndefinedSpecs(PyObject *keyws, char *&DK, char *&DC);
2063
2064
2065bool readBoolFlag(PyObject *keywords, char *flag)
2066{
2067  PyObject *pyflag = keywords ? PyDict_GetItemString(keywords, flag) : PYNULL;
2068  return pyflag && PyObject_IsTrue(pyflag);
2069}
2070
2071bool hasFlag(PyObject *keywords, char *flag)
2072{
2073  return keywords && (PyDict_GetItemString(keywords, flag) != PYNULL);
2074}
2075
2076
2077TExampleTable         *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);
2078TExampleGenerator *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);
2079
2080PyObject *encodeStatus(const vector<int> &status);
2081PyObject *encodeStatus(const vector<pair<int, int> > &metaStatus);
2082
2083char *obsoleteFlags[] = {"dontCheckStored", "dontStore", "use", "useMetas", "domain", 0 };
2084
2085
2086PyObject *loadDataFromFileNoSearch(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2087{
2088  PyObject *res;
2089
2090  bool pythonFileFound;
2091  res = loadDataByPython(type, filename, argstuple, keywords, false, pythonFileFound);
2092  if (res) {
2093    if (res != Py_None) {
2094      if (!PyTuple_Check(res))
2095        return res;
2096
2097      PyObject *pygen = PyTuple_GetItem(res, 0);
2098      Py_INCREF(pygen);
2099
2100      if (PyTuple_Size(res) >= 2) {
2101        Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", PyTuple_GET_ITEM(res, 1), false);
2102        Orange_setattrDictionary((TPyOrange *)pygen, "attribute_load_status", PyTuple_GET_ITEM(res, 1), false);
2103      }
2104      if (PyTuple_Size(res) >= 3) {
2105        Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", PyTuple_GET_ITEM(res, 2), false);
2106        Orange_setattrDictionary((TPyOrange *)pygen, "meta_attribute_load_status", PyTuple_GET_ITEM(res, 2), false);
2107      }
2108      return pygen;
2109    }
2110
2111    else
2112      Py_DECREF(Py_None);
2113  }
2114
2115  PyErr_Clear();
2116
2117  for(char * const *of = obsoleteFlags; *of; of++)
2118    if (hasFlag(keywords, *of))
2119      raiseWarning("flag '%s' is not supported any longer", *of);
2120
2121  int createNewOn = TVariable::Incompatible;
2122  if (hasFlag(keywords, "createNewOn"))
2123    convertFromPython(PyDict_GetItemString(keywords, "createNewOn"), createNewOn);
2124
2125  char *DK = NULL, *DC = NULL;
2126  if (!readUndefinedSpecs(keywords, DK, DC))
2127    return PYNULL;
2128
2129  char *errs = NULL;
2130  vector<int> status;
2131  vector<pair<int, int> > metaStatus;
2132  try {
2133    TExampleGenerator *generator =
2134      generatorOnly ? readGenerator(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"))
2135                    : readTable(filename, createNewOn, status, metaStatus, DK, DC, false, readBoolFlag(keywords, "noCodedDiscrete"), readBoolFlag(keywords, "noClass"));
2136    if (generator) {
2137      PyObject *pygen = WrapNewOrange(generator, type);
2138      PyObject *pystatus = encodeStatus(status);
2139      PyObject *pymetastatus = encodeStatus(metaStatus);
2140      Orange_setattrDictionary((TPyOrange *)pygen, "attributeLoadStatus", pystatus, false);
2141      Orange_setattrDictionary((TPyOrange *)pygen, "metaAttributeLoadStatus", pymetastatus, false);
2142      Py_DECREF(pystatus);
2143      Py_DECREF(pymetastatus);
2144      return pygen;
2145    }
2146  }
2147  catch (mlexception err) {
2148    errs = strdup(err.what());
2149  }
2150
2151  res = loadDataByPython(type, filename, argstuple, keywords, true, pythonFileFound);
2152  if (res)
2153    return res;
2154
2155  if (pythonFileFound) {
2156    PYERROR(PyExc_SystemError, "cannot load the file", PYNULL);
2157  }
2158  else {
2159    PyErr_SetString(PyExc_SystemError, errs);
2160    free(errs);
2161    return PYNULL;
2162  }
2163}
2164
2165PyObject *loadDataFromFilePath(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly, const char *path)
2166{
2167  if (!path) {
2168    return NULL;
2169  }
2170
2171  #if defined _WIN32
2172  const char sep = ';';
2173  const char pathsep = '\\';
2174  #else
2175  const char sep = ':';
2176  const char pathsep = '/';
2177  #endif
2178  const int flen = strlen(filename);
2179
2180  for(const char *pi = path, *pe=pi; *pi; pi = pe+1) {
2181    for(pe = pi; *pe && *pe != sep; pe++);
2182    const int plen = pe-pi;
2183    char *npath = new char[plen + flen + 2];
2184    strncpy(npath, pi, pe - pi);
2185    if (!plen || (pi[plen] != pathsep)) {
2186      npath[plen] = pathsep;
2187      strcpy(npath+plen+1, filename);
2188    }
2189    else {
2190      strcpy(npath+plen, filename);
2191    }
2192    PyObject *res = loadDataFromFileNoSearch(type, npath, argstuple, keywords, generatorOnly);
2193    delete[] npath;
2194
2195    PyErr_Clear();
2196    if (res) {
2197      return res;
2198    }
2199    if (!*pe)
2200      break;
2201  }
2202
2203  return NULL;
2204}
2205
2206PyObject *loadDataFromFile(PyTypeObject *type, char *filename, PyObject *argstuple, PyObject *keywords, bool generatorOnly = false)
2207{
2208  PyObject *ptype, *pvalue, *ptraceback;
2209  PyObject *res;
2210
2211  res = loadDataFromFileNoSearch(type, filename, argstuple, keywords, generatorOnly);
2212  if (res) {
2213    return res;
2214  }
2215
2216  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
2217
2218  // Try to find the file in the doc/datasets directory
2219  PyObject *configurationModule = PyImport_ImportModule("orngConfiguration");
2220  if (configurationModule) {
2221    PyObject *datasetsPath = PyDict_GetItemString(PyModule_GetDict(configurationModule), "datasetsPath");
2222    if (datasetsPath)
2223      res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, PyString_AsString(datasetsPath));
2224    Py_DECREF(configurationModule);
2225  }
2226  else {
2227    PyErr_Clear();
2228  }
2229
2230  if (!res) {
2231      // Try fo find the file using Orange.data.io.find_file
2232      PyObject *ioModule = PyImport_ImportModule("Orange.data.io");
2233      if (ioModule) {
2234          PyObject *find_file = PyObject_GetAttrString(ioModule, "find_file");
2235          if (find_file){
2236              PyObject *py_args = Py_BuildValue("(s)", filename);
2237              PyObject *ex_filename = PyObject_Call(find_file, py_args, NULL);
2238              if (ex_filename && PyString_Check(ex_filename)){
2239                  res = loadDataFromFileNoSearch(type, PyString_AsString(ex_filename), argstuple, keywords, generatorOnly);
2240                  Py_DECREF(ex_filename);
2241              }
2242              PyErr_Clear();
2243              Py_DECREF(py_args);
2244              Py_DECREF(find_file);
2245          }
2246          Py_DECREF(ioModule);
2247      }
2248  }
2249  if (!res)
2250      PyErr_Clear();
2251
2252  if (!res) {
2253    res = loadDataFromFilePath(type, filename, argstuple, keywords, generatorOnly, getenv("ORANGE_DATA_PATH"));
2254  }
2255
2256  if (res) {
2257    Py_XDECREF(ptype);
2258    Py_XDECREF(pvalue);
2259    Py_XDECREF(ptraceback);
2260    return res;
2261  }
2262
2263  PyErr_Restore(ptype, pvalue, ptraceback);
2264  return PYNULL;
2265}
2266
2267
2268int pt_ExampleGenerator(PyObject *args, void *egen)
2269{
2270  *(PExampleGenerator *)(egen) = PyOrExampleGenerator_Check(args) ? PyOrange_AsExampleGenerator(args)
2271                                                                  : PExampleGenerator(readListOfExamples(args));
2272
2273  if (!*(PExampleGenerator *)(egen))
2274    PYERROR(PyExc_TypeError, "invalid example generator", 0)
2275  else
2276    return 1;
2277}
2278
2279
2280static PDomain ptd_domain;
2281
2282int ptdf_ExampleGenerator(PyObject *args, void *egen)
2283{
2284  egen = NULL;
2285
2286  try {
2287    if (PyOrExampleGenerator_Check(args)) {
2288      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
2289      if (gen->domain == ptd_domain)
2290        *(PExampleGenerator *)(egen) = gen;
2291      else
2292        *(PExampleGenerator *)(egen) = mlnew TExampleTable(ptd_domain, gen);
2293    }
2294    else
2295      *(PExampleGenerator *)(egen) = PExampleGenerator(readListOfExamples(args, ptd_domain));
2296
2297    ptd_domain = PDomain();
2298
2299    if (!*(PExampleGenerator *)(egen))
2300      PYERROR(PyExc_TypeError, "invalid example generator", 0)
2301    else
2302      return 1;
2303  }
2304
2305  catch (...) {
2306    ptd_domain = PDomain();
2307    throw;
2308  }
2309}
2310
2311
2312converter ptd_ExampleGenerator(PDomain domain)
2313{
2314  ptd_domain = domain;
2315  return ptdf_ExampleGenerator;
2316}
2317
2318
2319CONSTRUCTOR_KEYWORDS(ExampleGenerator, "domain use useMetas dontCheckStored dontStore filterMetas DC DK NA noClass noCodedDiscrete")
2320
2321// Class ExampleGenerator is abstract in C++; this constructor returns the derived classes
2322
2323NO_PICKLE(ExampleGenerator)
2324
2325PyObject *ExampleGenerator_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(Orange, "(filename)")
2326{
2327  PyTRY
2328    char *filename = NULL;
2329    if (PyArg_ParseTuple(argstuple, "s", &filename))
2330      return loadDataFromFile(type, filename, argstuple, keywords, true);
2331    else
2332      return PYNULL;
2333  PyCATCH;
2334}
2335
2336
2337PExampleGenerator exampleGenFromParsedArgs(PyObject *args)
2338{
2339 if (PyOrOrange_Check(args)) {
2340   if (PyOrExampleGenerator_Check(args))
2341      return PyOrange_AsExampleGenerator(args);
2342    else
2343      PYERROR(PyExc_TypeError, "example generator expected", NULL);
2344  }
2345  return PExampleGenerator(readListOfExamples(args));
2346}
2347
2348
2349PExampleGenerator exampleGenFromArgs(PyObject *args, int &weightID)
2350{
2351  PyObject *examples, *pyweight = NULL;
2352  if (!PyArg_UnpackTuple(args, "exampleGenFromArgs", 1, 2, &examples, &pyweight))
2353    return PExampleGenerator();
2354
2355  PExampleGenerator egen = exampleGenFromParsedArgs(examples);
2356  if (!egen || !weightFromArg_byDomain(pyweight, egen->domain, weightID))
2357    return PExampleGenerator();
2358
2359  return egen;
2360}
2361
2362
2363PExampleGenerator exampleGenFromArgs(PyObject *args)
2364{
2365  if (PyTuple_GET_SIZE(args) != 1)
2366    PYERROR(PyExc_TypeError, "exampleGenFromArgs: examples expected", PExampleGenerator())
2367
2368  return exampleGenFromParsedArgs(PyTuple_GET_ITEM(args, 0));
2369}
2370
2371
2372PyObject *ExampleGenerator_native(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
2373{ PyTRY
2374    bool tuples = false;
2375    PyObject *forDC = NULL;
2376    PyObject *forDK = NULL;
2377    PyObject *forSpecial = NULL;
2378    if (keyws) {
2379      PyObject *pytuples = PyDict_GetItemString(keyws, "tuple");
2380      tuples = pytuples && (PyObject_IsTrue(pytuples) != 0);
2381
2382      forDC = PyDict_GetItemString(keyws, "substitute_DC");
2383      if (!forDC) {
2384          forDC = PyDict_GetItemString(keyws, "substituteDC");
2385      }
2386      forDC = PyDict_GetItemString(keyws, "substitute_DK");
2387      if (!forDC) {
2388          forDC = PyDict_GetItemString(keyws, "substituteDK");
2389      }
2390      forDC = PyDict_GetItemString(keyws, "substitute_other");
2391      if (!forDC) {
2392          forDC = PyDict_GetItemString(keyws, "substituteOther");
2393      }
2394    }
2395
2396    int natvt=2;
2397    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=2)))
2398      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2399    CAST_TO(TExampleGenerator, eg);
2400
2401    PyObject *list=PyList_New(0);
2402    EITERATE(ei, *eg)
2403      if (natvt<=1) {
2404        PyObject *obj=convertToPythonNative(*ei, natvt, tuples, forDK, forDC, forSpecial);
2405        PyList_Append(list, obj);
2406        Py_DECREF(obj);
2407      }
2408        // What happens with: convertToPythonNative((*ei, natvt, tuples))? Funny.
2409      else {
2410        PyObject *example=Example_FromExampleCopyRef(*ei);
2411        if (!example) {
2412          PyMem_DEL(list);
2413          PYERROR(PyExc_SystemError, "out of memory", PYNULL);
2414        }
2415        PyList_Append(list, example);
2416        Py_DECREF(example);
2417      }
2418
2419    return list;
2420  PyCATCH
2421}
2422
2423
2424PVariableFilterMap PVariableFilterMap_FromArguments(PyObject *arg);
2425
2426int VariableFilterMap_setitemlow(TVariableFilterMap *aMap, PVariable var, PyObject *pyvalue);
2427
2428inline PVariableFilterMap sameValuesMap(PyObject *dict, PDomain dom)
2429{ TVariableFilterMap *vfm = mlnew TVariableFilterMap;
2430  PVariableFilterMap wvfm = vfm;
2431
2432  Py_ssize_t pos=0;
2433  PyObject *pykey, *pyvalue;
2434  while (PyDict_Next(dict, &pos, &pykey, &pyvalue)) {
2435    PVariable var = varFromArg_byDomain(pykey, dom, true);
2436    if (!var || (VariableFilterMap_setitemlow(vfm, var, pyvalue) < 0))
2437      return PVariableFilterMap();
2438  }
2439
2440  return wvfm;
2441}
2442
2443inline PPreprocessor pp_sameValues(PyObject *dict, PDomain dom)
2444{ PVariableFilterMap vfm = sameValuesMap(dict, dom);
2445  return vfm ? mlnew TPreprocessor_take(vfm) : PPreprocessor();
2446}
2447
2448inline PFilter filter_sameValues(PyObject *dict, PDomain domain, PyObject *kwds = PYNULL)
2449{ PVariableFilterMap svm = sameValuesMap(dict, domain);
2450  if (!svm)
2451    return PFilter();
2452
2453  PyObject *pyneg = kwds ? PyDict_GetItemString(kwds, "negate") : NULL;
2454  return TPreprocessor_take::constructFilter(svm, domain, true, pyneg && PyObject_IsTrue(pyneg));
2455}
2456
2457PyObject *applyPreprocessor(PPreprocessor preprocessor, PExampleGenerator gen, bool weightGiven, int weightID)
2458{ if (!preprocessor)
2459    return PYNULL;
2460
2461  int newWeight;
2462  PExampleGenerator newGen = preprocessor->call(gen, weightID, newWeight);
2463  return weightGiven ? Py_BuildValue("Ni", WrapOrange(newGen), newWeight) : WrapOrange(newGen);
2464}
2465
2466
2467
2468PyObject *applyFilter(PFilter filter, PExampleGenerator gen, bool weightGiven, int weightID);
2469
2470PyObject *ExampleGenerator_select(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
2471/* This function is a spaghetti for compatibility reasons. Most of its functionality
2472   has been moved to specialized functions (changeDomain, filter). The only two
2473   functions that 'select' should be used for is selection of examples by vector
2474   of bools or indices (LongList) */
2475{
2476  PyTRY
2477    CAST_TO(TExampleGenerator, eg);
2478    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2479
2480    /* ***** SELECTION BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
2481    /* Deprecated: use method 'filter' instead */
2482    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2483      return applyPreprocessor(pp_sameValues(keywords, eg->domain), weg, false, 0);
2484    }
2485
2486
2487    PyObject *mplier;
2488    PyObject *pyweight = NULL;
2489    if (PyArg_ParseTuple(args, "O|O", &mplier, &pyweight)) {
2490      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
2491      bool negate = pyneg && PyObject_IsTrue(pyneg);
2492      bool secondArgGiven = (pyweight != NULL);
2493
2494      /* ***** SELECTION BY VECTOR OF BOOLS ****** */
2495      if (PyList_Check(mplier) && PyList_Size(mplier) && PyInt_Check(PyList_GetItem(mplier, 0))) {
2496        Py_ssize_t nole = PyList_Size(mplier);
2497
2498        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2499        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2500        Py_ssize_t i = 0;
2501
2502        if (secondArgGiven) {
2503          if (PyInt_Check(pyweight)) {
2504            int compVal = (int)PyInt_AsLong(pyweight);
2505            TExampleIterator ei = eg->begin();
2506            for(; ei && (i<nole); ++ei) {
2507              PyObject *lel = PyList_GetItem(mplier, i++);
2508              if (!PyInt_Check(lel))
2509                break;
2510
2511              if (negate != (PyInt_AsLong(lel)==compVal))
2512                newTable->addExample(*ei);
2513            }
2514
2515            if ((i==nole) && !ei)
2516              return WrapOrange(newGen);
2517          }
2518        }
2519        else {
2520          TExampleIterator ei = eg->begin();
2521          for(; ei && (i<nole); ++ei) {
2522            PyObject *lel = PyList_GetItem(mplier, i++);
2523            if (negate != (PyObject_IsTrue(lel) != 0))
2524              newTable->addExample(*ei);
2525          }
2526
2527          if ((i==nole) && !ei)
2528            return WrapOrange(newGen);
2529        }
2530      }
2531
2532      PyErr_Clear();
2533
2534
2535      /* ***** SELECTION BY LONGLIST ****** */
2536      if (PyOrLongList_Check(mplier)) {
2537        PLongList llist = PyOrange_AsLongList(mplier);
2538        TLongList::iterator lli(llist->begin()), lle(llist->end());
2539
2540        TExampleTable *newTable = mlnew TExampleTable(eg->domain);
2541        PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
2542
2543        TExampleIterator ei = eg->begin();
2544
2545        if (secondArgGiven) {
2546          if (!PyInt_Check(pyweight))
2547            PYERROR(PyExc_AttributeError, "example selector must be an integer", PYNULL);
2548
2549          int compVal = (int)PyInt_AsLong(pyweight);
2550          for(; ei && (lli!=lle); ++ei, lli++)
2551            if (negate != (*lli==compVal))
2552              newTable->addExample(*ei);
2553        }
2554        else {
2555          for(; ei && (lli != lle); ++ei, lli++)
2556            if (negate != (*lli != 0))
2557              newTable->addExample(*ei);
2558        }
2559
2560        if ((lli==lle) && !ei)
2561          return WrapOrange(newGen);
2562
2563        PYERROR(PyExc_IndexError, "ExampleGenerator.select: invalid list size", PYNULL)
2564      }
2565
2566      PyErr_Clear();
2567
2568      /* ***** CHANGING DOMAIN ***** */
2569      /* Deprecated: use method 'translate' instead. */
2570      if (PyOrDomain_Check(mplier)) {
2571        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(PyOrange_AsDomain(mplier), weg)));
2572        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2573      }
2574
2575
2576      /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2577      /* Deprecated: use method 'translate' instead. */
2578      TVarList attributes;
2579      if (varListFromDomain(mplier, eg->domain, attributes, true, false)) {
2580        PDomain newDomain;
2581        TVarList::iterator vi, ve;
2582        for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2583        if (vi==ve)
2584          newDomain = mlnew TDomain(PVariable(), attributes);
2585        else {
2586          attributes.erase(vi);
2587          newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2588        }
2589
2590        PyObject *wrappedGen = WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2591        return secondArgGiven ? Py_BuildValue("NO", wrappedGen, pyweight) : wrappedGen;
2592      }
2593
2594      PyErr_Clear();
2595
2596
2597      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
2598      /* Deprecated: use method 'filter' instead. */
2599      if (PyDict_Check(mplier)) {
2600        int weightID;
2601        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2602          return applyFilter(filter_sameValues(mplier, eg->domain), weg, secondArgGiven, weightID);
2603      }
2604
2605
2606      /* ***** PREPROCESSING ***** */
2607      /* Deprecated: call preprocessor instead. */
2608      if (PyOrPreprocessor_Check(mplier)) {
2609        int weightID;
2610        if (weightFromArg_byDomain(pyweight, eg->domain, weightID)) {
2611
2612          PExampleGenerator res;
2613          int newWeight;
2614          PyTRY
2615            NAME_CAST_TO(TPreprocessor, mplier, pp);
2616            if (!pp)
2617              PYERROR(PyExc_TypeError, "invalid object type (preprocessor announced, but not passed)", PYNULL)
2618            res = (*pp)(weg, weightID, newWeight);
2619          PyCATCH
2620
2621          return secondArgGiven ? Py_BuildValue("Ni", WrapOrange(res), newWeight) : WrapOrange(res);
2622        }
2623      }
2624
2625      /* ***** APPLY FILTER ***** */
2626      /* Deprecated: use method 'filter' instead. */
2627      if (PyOrFilter_Check(mplier)) {
2628        int weightID;
2629        if (weightFromArg_byDomain(pyweight, eg->domain, weightID))
2630          return applyFilter(PyOrange_AsFilter(mplier), weg, secondArgGiven, weightID);
2631      }
2632    }
2633    PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
2634  PyCATCH
2635}
2636
2637
2638PyObject *ExampleGenerator_filter(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
2639{
2640  PyTRY
2641    CAST_TO(TExampleGenerator, eg);
2642    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2643
2644    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
2645      return applyFilter(filter_sameValues(keywords, eg->domain, keywords), weg, false, 0);
2646    }
2647
2648    if (PyTuple_Size(args)==1) {
2649      PyObject *arg = PyTuple_GET_ITEM(args, 0);
2650
2651      if (PyDict_Check(arg))
2652        return applyFilter(filter_sameValues(arg, eg->domain, keywords), weg, false, 0);
2653
2654      if (PyOrFilter_Check(arg))
2655          return applyFilter(PyOrange_AsFilter(arg), weg, false, 0);
2656    }
2657
2658    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter expects a list of conditions or orange.Filter", PYNULL)
2659  PyCATCH
2660}
2661
2662
2663PyObject *ExampleGenerator_translate(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "translate(domain | list-of-attributes) -> ExampleTable")
2664{
2665  PyTRY
2666    CAST_TO(TExampleGenerator, eg);
2667    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
2668
2669    PDomain domain;
2670    if (PyArg_ParseTuple(args, "O&|i", cc_Domain, &domain))
2671      return WrapOrange(PExampleTable(mlnew TExampleTable(domain, weg)));
2672
2673    PyObject *pargs, *guard = NULL;
2674    int keepMeta = 0;
2675    if (args && ((PyTuple_Size(args)==1) || ((PyTuple_Size(args)==2) && PyInt_Check(PyTuple_GET_ITEM(args, 1))))) {
2676      pargs = guard = PyTuple_GET_ITEM(args, 0);
2677      if (PyTuple_Size(args)==2) {
2678        keepMeta = PyInt_AsLong(PyTuple_GET_ITEM(args, 1));
2679      }
2680    }
2681    else
2682      pargs = args;
2683
2684    /* ***** SELECTION BY VECTOR OF NAMES, INDICES AND VARIABLES ****** */
2685    TVarList attributes;
2686    if (varListFromDomain(pargs, eg->domain, attributes, true, false)) {
2687      PDomain newDomain;
2688      TVarList::iterator vi, ve;
2689      for(vi = attributes.begin(), ve = attributes.end(); (vi!=ve) && (*vi!=eg->domain->classVar); vi++);
2690      if (vi==ve)
2691        newDomain = mlnew TDomain(PVariable(), attributes);
2692      else {
2693        attributes.erase(vi);
2694        newDomain = mlnew TDomain(eg->domain->classVar, attributes);
2695      }
2696     
2697      if (keepMeta) {
2698        newDomain->metas = eg->domain->metas;
2699      }
2700
2701      Py_XDECREF(guard);
2702      return WrapOrange(PExampleTable(mlnew TExampleTable(newDomain, weg)));
2703    }
2704
2705    PYERROR(PyExc_AttributeError, "ExampleGenerator.translate expects a list of attributes or orange.Domain", PYNULL)
2706 PyCATCH
2707}
2708
2709
2710PyObject *multipleSelectLow(TPyOrange *self, PyObject *pylist, bool reference)
2711{ PyTRY
2712    if (!PyList_Check(pylist))
2713      PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2714
2715    vector<int> indices;
2716    Py_ssize_t i, sze = PyList_Size(pylist);
2717    for(i = 0; i<sze; i++) {
2718      PyObject *lel = PyList_GetItem(pylist, i);
2719      if (!PyInt_Check(lel))
2720        PYERROR(PyExc_TypeError, "a list of example indices expected", PYNULL);
2721      indices.push_back(int(PyInt_AsLong(lel)));
2722    }
2723    sort(indices.begin(), indices.end());
2724
2725    CAST_TO(TExampleGenerator, eg);
2726    TExampleTable *newTable = reference ? mlnew TExampleTable(eg, (int)0)
2727                                        : mlnew TExampleTable(eg->domain);
2728    PExampleGenerator newGen(newTable);
2729
2730    TExampleGenerator::iterator ei(eg->begin());
2731    vector<int>::iterator ii(indices.begin()), iie(indices.end());
2732    i = 0;
2733    while(ei && (ii!=iie)) {
2734      if (*ii == i) {
2735        newTable->addExample(*ei);
2736        ii++;
2737      }
2738      else {
2739        i++;
2740        ++ei;
2741      }
2742    }
2743
2744    if (ii!=iie)
2745      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
2746
2747    return WrapOrange(newGen);
2748  PyCATCH
2749}
2750
2751
2752PyObject *ExampleGenerator_get_items(TPyOrange *self, PyObject *pylist)  PYARGS(METH_O, "(indices) -> ExampleTable")
2753{ return multipleSelectLow(self, pylist, false); }
2754
2755
2756PyObject *ExampleGenerator_checksum(PyObject *self, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
2757{ PyTRY
2758    return PyInt_FromLong(SELF_AS(TExampleGenerator).checkSum());
2759  PyCATCH
2760}
2761
2762
2763const char *getExtension(const char *name);
2764char *getFileSystemEncoding(); // defined in lib_io.cpp
2765
2766PyObject *saveTabDelimited(PyObject *, PyObject *args, PyObject *keyws);
2767PyObject *saveC45(PyObject *, PyObject *args);
2768PyObject *saveTxt(PyObject *, PyObject *args, PyObject *keyws);
2769PyObject *saveCsv(PyObject *, PyObject *args, PyObject *keyws);
2770PyObject *saveBasket(PyObject *, PyObject *args);
2771
2772PyObject *ExampleGenerator_save(PyObject *self, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "(filename) -> None")
2773{
2774  char *filename;
2775  bool free_filename = false;
2776  if (!PyArg_ParseTuple(args, "s:ExampleGenerator.save", &filename))
2777  {
2778      // Try again, this time with the fs encoding.
2779      char *encoding = getFileSystemEncoding();
2780      if (!PyArg_ParseTuple(args, "es:ExampleGenerator.save", encoding, &filename))
2781          return PYNULL;
2782      free_filename = true;
2783      PyErr_Clear();
2784  }
2785
2786  const char *extension = getExtension(filename);
2787  if (!extension)
2788  {
2789    if (free_filename)
2790        PyMem_Free(filename);
2791    PYERROR(PyExc_TypeError, "file name must have an extension", PYNULL);
2792  }
2793
2794
2795  PyObject *newargs = PyTuple_New(PyTuple_Size(args) + 1);
2796  PyObject *el;
2797
2798  el = PyTuple_GET_ITEM(args, 0);
2799  Py_INCREF(el);
2800  PyTuple_SetItem(newargs, 0, el);
2801
2802  Py_INCREF(self);
2803  PyTuple_SetItem(newargs, 1, self);
2804
2805  for(Py_ssize_t i = 1, e = PyTuple_Size(args); i < e; i++) {
2806    el = PyTuple_GET_ITEM(args, i);
2807    Py_INCREF(el);
2808    PyTuple_SetItem(newargs, i+1, el);
2809  }
2810
2811  PyObject *res = PYNULL;
2812
2813  vector<TFiletypeDefinition>::iterator fi = findFiletypeByExtension(filename, false, true, false);
2814  if (fi != filetypeDefinitions.end())
2815    res = PyObject_Call((*fi).saver, newargs, keyws);
2816  else if (!strcmp(extension, ".tab"))
2817    res = saveTabDelimited(NULL, newargs, keyws);
2818  else if (!strcmp(extension, ".txt"))
2819    res = saveTxt(NULL, newargs, keyws);
2820  else if (!strcmp(extension, ".csv"))
2821    res = saveCsv(NULL, newargs, keyws);
2822  else if (!strcmp(extension, ".names") || !strcmp(extension, ".data") || !strcmp(extension, ".test"))
2823    res = saveC45(NULL, newargs);
2824  else if (!strcmp(extension, ".basket"))
2825    res = saveBasket(NULL, newargs);
2826  else
2827    PyErr_Format(PyExc_AttributeError, "unknown file format (%s)", extension);
2828
2829  Py_DECREF(newargs);
2830
2831  if (free_filename)
2832      PyMem_Free(filename);
2833
2834  return res;
2835}
2836
2837
2838PyObject *ExampleGenerator_weight(PyObject *self, PyObject *args, PyObject *) PYARGS(METH_VARARGS, "(weightID)")
2839{
2840  PyObject *pyw = PYNULL;
2841  if (!PyArg_ParseTuple(args, "|O:ExampleGenerator.weight", &pyw))
2842    return PYNULL;
2843
2844  CAST_TO(TExampleGenerator, egen)
2845  if (!pyw)
2846    return PyInt_FromLong(egen->numberOfExamples());
2847
2848  int weightID;
2849  if (!varNumFromVarDom(pyw, egen->domain, weightID))
2850    return PYNULL;
2851
2852  float weight = 0.0;
2853  PEITERATE(ei, egen)
2854    weight += WEIGHT(*ei);
2855
2856  return PyFloat_FromDouble(weight);
2857}
2858
2859
2860PExampleGeneratorList PExampleGeneratorList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::P_FromArguments(arg); }
2861PyObject *ExampleGeneratorList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_FromArguments(type, arg); }
2862PyObject *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); }
2863PyObject *ExampleGeneratorList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getitem(self, index); }
2864int       ExampleGeneratorList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_setitem(self, index, item); }
2865PyObject *ExampleGeneratorList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_getslice(self, start, stop); }
2866int       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); }
2867Py_ssize_t       ExampleGeneratorList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_len(self); }
2868PyObject *ExampleGeneratorList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_richcmp(self, object, op); }
2869PyObject *ExampleGeneratorList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_concat(self, obj); }
2870PyObject *ExampleGeneratorList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_repeat(self, times); }
2871PyObject *ExampleGeneratorList_str(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2872PyObject *ExampleGeneratorList_repr(TPyOrange *self) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_str(self); }
2873int       ExampleGeneratorList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_contains(self, obj); }
2874PyObject *ExampleGeneratorList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_append(self, item); }
2875PyObject *ExampleGeneratorList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_extend(self, obj); }
2876PyObject *ExampleGeneratorList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_count(self, obj); }
2877PyObject *ExampleGeneratorList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> ExampleGeneratorList") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_filter(self, args); }
2878PyObject *ExampleGeneratorList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> int") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_index(self, obj); }
2879PyObject *ExampleGeneratorList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_insert(self, args); }
2880PyObject *ExampleGeneratorList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_native(self); }
2881PyObject *ExampleGeneratorList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> ExampleGenerator") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_pop(self, args); }
2882PyObject *ExampleGeneratorList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(ExampleGenerator) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_remove(self, obj); }
2883PyObject *ExampleGeneratorList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reverse(self); }
2884PyObject *ExampleGeneratorList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_sort(self, args); }
2885PyObject *ExampleGeneratorList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PExampleGeneratorList, TExampleGeneratorList, PExampleGenerator, &PyOrExampleGenerator_Type>::_reduce(self); }
2886
2887
2888/* ************ EXAMPLE TABLE ************ */
2889
2890#include "table.hpp"
2891#include "numeric_interface.hpp"
2892
2893TExampleTable *readListOfExamples(PyObject *args)
2894{
2895    if (isSomeNumeric_wPrecheck(args) || isSomeMaskedNumeric_wPrecheck(args))
2896      return readListOfExamples(args, PDomain(), false);
2897
2898
2899  if (PySequence_Check(args)) {
2900    Py_ssize_t size=PySequence_Size(args);
2901    if (!size)
2902      PYERROR(PyExc_TypeError, "can't construct a table from an empty sequence", (TExampleTable *)NULL);
2903
2904    TExampleTable *table=NULL;
2905    PyObject *pex = NULL;
2906
2907    try {
2908      for(Py_ssize_t i=0; i<size; i++) {
2909        PyObject *pex = PySequence_GetItem(args, i);
2910        if (!pex || !PyOrExample_Check(pex)) {
2911          Py_XDECREF(pex);
2912          mldelete table;
2913          PyErr_Format(PyExc_TypeError, "invalid sequence element at %i", i);
2914          return NULL;
2915        }
2916        if (!i)
2917          table = mlnew TExampleTable(PyExample_AS_Example(pex)->domain);
2918        table->addExample(PyExample_AS_ExampleReference(pex));
2919        Py_DECREF(pex);
2920        pex = NULL;
2921      }
2922    }
2923    catch (...) {
2924      delete table;
2925      Py_XDECREF(pex);
2926      throw;
2927    }
2928
2929    return table;
2930  }
2931
2932  PYERROR(PyExc_TypeError, "a list of examples expected", NULL);
2933}
2934
2935
2936
2937template<typename T>
2938int to_int_value(T & value) {
2939    return (int)value;
2940}
2941
2942
2943template<>
2944int to_int_value<float>(float & value) {
2945    return (int)floor(0.5 + value);
2946}
2947
2948
2949template<>
2950int to_int_value<double>(double & value) {
2951    return (int)floor(0.5 + value);
2952}
2953
2954
2955template<typename T>
2956void init_value(TValue & target, TVariable & variable, T & value, bool masked=false) {
2957    if (variable.varType == TValue::INTVAR) {
2958        TEnumVariable * enumvar = dynamic_cast<TEnumVariable *>(&variable);
2959        int ivalue = to_int_value(value);
2960        if (enumvar) {
2961            if (!masked && (ivalue < 0 || ivalue >= enumvar->noOfValues())) {
2962                PyErr_Format(PyExc_ValueError, "Invalid value for a Discrete variable.");
2963                throw pyexception();
2964            }
2965        }
2966        intValInit(target, ivalue, masked ? valueDK : valueRegular);
2967    } else {
2968        floatValInit(target, (float)value,  masked ? valueDK : valueRegular);
2969    }
2970}
2971
2972
2973template<typename T>
2974void copy_strided_buffer_to_example(
2975        TExample & example,
2976        char * buffer, Py_ssize_t stride,
2977        char * mask_buffer, Py_ssize_t mask_stride) {
2978    PDomain domain = example.domain;
2979    PVarList vars = domain->variables, class_vars = domain->classVars;
2980    TVarList::iterator var_iter = vars->begin();
2981    TValue * value_iter = example.begin();
2982    int pos = 0;
2983
2984    // copy variables part
2985    for (; var_iter != vars->end();
2986            var_iter++, value_iter++, pos++) {
2987        init_value(*value_iter, var_iter->getReference(),
2988                   *((T *) buffer), mask_buffer && (*mask_buffer));
2989
2990        buffer += stride;
2991        if (mask_buffer) {
2992            mask_buffer += mask_stride;
2993        }
2994    }
2995
2996    // copy class vars part
2997    for (var_iter = class_vars->begin();
2998            var_iter != class_vars->end();
2999            var_iter++, value_iter++, pos++) {
3000        init_value(*value_iter, var_iter->getReference(),
3001                   *((T *) buffer), mask_buffer && (*mask_buffer));
3002
3003        buffer += stride;
3004        if (mask_buffer) {
3005        mask_buffer += mask_stride;
3006        }
3007    }
3008}
3009
3010
3011TExampleTable *readListOfExamples(PyObject *args, PDomain domain, bool filterMetas)
3012{
3013  PyArrayObject *array = NULL, *mask = NULL;
3014
3015  if (isSomeNumeric_wPrecheck(args)) {
3016    array = (PyArrayObject *)args;
3017  } else if (isSomeMaskedNumeric_wPrecheck(args)) {
3018    array = (PyArrayObject *)args;
3019    mask = (PyArrayObject *)PyObject_GetAttrString(args, "mask");
3020    if (!mask) {
3021        PyErr_Clear();
3022    } else if (!isSomeNumeric_wPrecheck((PyObject *)mask)) {
3023      Py_DECREF((PyObject *)mask);
3024      mask = NULL;
3025    }
3026  }
3027
3028  if (array) {
3029      if (array->nd != 2)
3030        PYERROR(PyExc_AttributeError, "two-dimensional array expected for an ExampleTable", NULL);
3031
3032      PVarList variables;
3033      TVarList::const_iterator vi;
3034
3035      if (!domain) {
3036        TVarList lvariables;
3037        char vbuf[20];
3038        for(int i = 0, e = array->dimensions[1]; i < e; i++) {
3039          sprintf(vbuf, "a%i", i+1);
3040          lvariables.push_back(mlnew TFloatVariable(vbuf));
3041        }
3042        domain = mlnew TDomain(PVariable(), lvariables);
3043        variables = domain->variables;
3044      }
3045
3046      else {
3047          int const nvars = domain->variables->size() + domain->classVars->size();
3048          if (array->dimensions[1] != nvars) {
3049              PyErr_Format(PyExc_AttributeError,
3050                  "the number of columns (%i) in the array doesn't match the number of attributes (%i)",
3051                  array->dimensions[1], nvars);
3052              return NULL;
3053          }
3054
3055       variables = domain->variables;
3056       for(vi = variables->begin(); vi!=variables->end(); vi++)
3057          if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
3058              PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
3059       
3060       for(vi = domain->classVars->begin(); vi!=domain->classVars->end(); vi++) 
3061          if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR))
3062              PYERROR(PyExc_TypeError, "cannot read the value of attribute '%s' from an array (unsupported attribute type)", NULL);
3063      }
3064
3065      const char arrayType = getArrayType(array);
3066      if (!strchr(supportedNumericTypes, arrayType)) {
3067        PyErr_Format(PyExc_AttributeError, "Converting arrays of type '%c' is not supported (use one of '%s')", arrayType, supportedNumericTypes);
3068        return NULL;
3069      }
3070
3071      TExampleTable *table = mlnew TExampleTable(domain);
3072      TExample *nex = NULL;
3073      table->reserve(array->dimensions[0]);
3074
3075      const int &strideRow = array->strides[0];
3076      const int &strideCol = array->strides[1];
3077
3078      // If there's no mask, the mask pointers will equal the data pointer to avoid too many if's
3079      const int &strideMaskRow = mask ? mask->strides[0] : strideRow;
3080      const int &strideMaskCol = mask ? mask->strides[1] : strideCol;
3081
3082      try {
3083        TExample::iterator ei;
3084        char *rowPtr = array->data;
3085        char *maskRowPtr = mask ? mask->data : array->data;
3086
3087        for (int row = 0, rowe = array->dimensions[0];
3088             row < rowe;
3089             row++, rowPtr += strideRow, maskRowPtr += strideMaskRow) {
3090          TExample *nex = mlnew TExample(domain);
3091          char * maskPtr = mask ? maskRowPtr : NULL;
3092
3093          #define COPY_BUFFER(TYPE) \
3094                  copy_strided_buffer_to_example<TYPE>(*nex, rowPtr, strideCol, maskPtr, strideMaskCol); \
3095                  break;
3096
3097          switch (arrayType) {
3098            case 'c':
3099            case 'b': COPY_BUFFER(char)
3100            case 'B': COPY_BUFFER(unsigned char)
3101            case 'h': COPY_BUFFER(short)
3102            case 'H': COPY_BUFFER(unsigned short)
3103            case 'i': COPY_BUFFER(int)
3104            case 'I': COPY_BUFFER(unsigned int)
3105            case 'l': COPY_BUFFER(long)
3106            case 'L': COPY_BUFFER(unsigned long)
3107            case 'f': COPY_BUFFER(float)
3108            case 'd': COPY_BUFFER(double)
3109          }
3110
3111          #undef COPY_BUFFER
3112
3113          table->addExample(nex);
3114          nex = NULL;
3115        }
3116      }
3117      catch (...) {
3118        mldelete table;
3119        mldelete nex;
3120        throw;
3121      }
3122
3123      return table;
3124  }
3125
3126  if (PyList_Check(args)) {
3127    Py_ssize_t size=PyList_Size(args);
3128    if (!size)
3129      PYERROR(PyExc_TypeError, "can't construct a table from an empty list", (TExampleTable *)NULL);
3130
3131    TExampleTable *table = mlnew TExampleTable(domain);;
3132
3133    try {
3134      for(Py_ssize_t i=0; i<size; i++) {
3135        PyObject *pex = PyList_GetItem(args, i);
3136        if (PyOrExample_Check(pex))
3137          table->addExample(PyExample_AS_ExampleReference(pex), filterMetas);
3138        else {
3139          TExample example(domain);
3140          if (!convertFromPythonExisting(pex, example)) {
3141            mldelete table;
3142            PyObject *type, *value, *tracebk;
3143            PyErr_Fetch(&type, &value, &tracebk);
3144            if (type) {
3145              //PyErr_Restore(type, value, tracebk);
3146              const char *oldes = PyString_AsString(value);
3147              PyErr_Format(type, "%s (at example %i)", oldes, i);
3148              Py_DECREF(type);
3149              Py_XDECREF(value);
3150              Py_XDECREF(tracebk);
3151              return NULL;
3152            }
3153          }
3154          table->addExample(example);
3155        }
3156      }
3157
3158      return table;
3159    }
3160    catch (...) {
3161      mldelete table;
3162      throw;
3163    }
3164  }
3165
3166  PYERROR(PyExc_TypeError, "invalid arguments", NULL);
3167}
3168
3169CONSTRUCTOR_KEYWORDS(ExampleTable, "domain use useMetas dontCheckStored dontStore filterMetas filter_metas DC DK NA noClass noCodedDiscrete createNewOn")
3170
3171PyObject *ExampleTable_new(PyTypeObject *type, PyObject *argstuple, PyObject *keywords) BASED_ON(ExampleGenerator - Orange.data.Table, "(filename | domain[, examples] | examples)")
3172{
3173  PyTRY
3174
3175    char *filename = NULL;
3176    if (PyArg_ParseTuple(argstuple, "s", &filename))
3177        return loadDataFromFile(type, filename, argstuple, keywords, false);
3178
3179    PyErr_Clear();
3180
3181    /*For a case where the unicode can't be converted to a default
3182     * encoding (on most platforms this is ASCII)
3183     */
3184    char * coding = getFileSystemEncoding();
3185    if (PyArg_ParseTuple(argstuple, "es", coding, &filename))
3186    {
3187        PyObject *rval = loadDataFromFile(type, filename, argstuple, keywords, false);
3188        PyMem_Free(filename);
3189        return rval;
3190    }
3191
3192    PyErr_Clear();
3193
3194    PExampleGenerator egen;
3195    PyObject *args = PYNULL;
3196    if (PyArg_ParseTuple(argstuple, "O&|O", cc_ExampleTable, &egen, &args))
3197      return WrapNewOrange(mlnew TExampleTable(egen, !args || (PyObject_IsTrue(args) == 0)), type);
3198
3199    PyErr_Clear();
3200
3201    if (PyArg_ParseTuple(argstuple, "O", &args)) {
3202      if (PyOrDomain_Check(args))
3203        return WrapNewOrange(mlnew TExampleTable(PyOrange_AsDomain(args)), type);
3204
3205      TExampleTable *res = readListOfExamples(args);
3206      if (res)
3207        return WrapNewOrange(res, type);
3208      PyErr_Clear();
3209
3210      // check if it's a list of generators
3211      if (PyList_Check(args)) {
3212        TExampleGeneratorList eglist;
3213        PyObject *iterator = PyObject_GetIter(args);
3214        PyObject *item = PyIter_Next(iterator);
3215        for(; item; item = PyIter_Next(iterator)) {
3216          if (!PyOrExampleGenerator_Check(item)) {
3217            Py_DECREF(item);
3218            break;
3219          }
3220          eglist.push_back(PyOrange_AsExampleGenerator(item));
3221          Py_DECREF(item);
3222        }
3223        Py_DECREF(iterator);
3224        if (!item)
3225          return WrapNewOrange(mlnew TExampleTable(PExampleGeneratorList(eglist)), type);
3226      }
3227
3228      PYERROR(PyExc_TypeError, "invalid arguments for constructor (domain or examples or both expected)", PYNULL);
3229    }
3230
3231    PyErr_Clear();
3232
3233    PDomain domain;
3234    if (PyArg_ParseTuple(argstuple, "O&O", cc_Domain, &domain, &args)) {
3235      bool filterMetas = readBoolFlag(keywords, "filterMetas") || readBoolFlag(keywords, "filter_metas");
3236
3237      if (PyOrExampleGenerator_Check(args))
3238        return WrapNewOrange(mlnew TExampleTable(domain, PyOrange_AsExampleGenerator(args), filterMetas), type);
3239      else {
3240        TExampleTable *res = readListOfExamples(args, domain, filterMetas);
3241        return res ? WrapNewOrange(res, type) : PYNULL;
3242      }
3243    }
3244
3245    PYERROR(PyExc_TypeError, "invalid arguments for ExampleTable.__init__", PYNULL);
3246
3247  PyCATCH
3248}
3249
3250
3251PyObject *ExampleTable__reduce__(PyObject *self)
3252{
3253  CAST_TO(TExampleTable, table)
3254
3255  if (!table->ownsExamples || table->lock) {
3256    PExampleTable lock = table->lock;
3257    TCharBuffer buf(1024);
3258    const int lockSize = lock->size();
3259    buf.writeInt(table->size());
3260    PEITERATE(ei, table) {
3261      int index = 0;
3262      PEITERATE(li, lock) {
3263        if (&*li == &*ei)
3264          break;
3265        index++;
3266      }
3267      if (index == lockSize) {
3268        PYERROR(PyExc_SystemError, "invalid example reference discovered in the table", PYNULL);
3269      }
3270
3271      buf.writeInt(index);
3272    }
3273
3274    return Py_BuildValue("O(ONs#)O", getExportedFunction("__pickleLoaderExampleReferenceTable"),
3275                                      self->ob_type,
3276                                      WrapOrange(table->lock),
3277                                      buf.buf, buf.length(),
3278                                      packOrangeDictionary(self));
3279  }
3280
3281  else {
3282    TCharBuffer buf(1024);
3283    PyObject *otherValues = NULL;
3284
3285    buf.writeInt(table->size());
3286    PEITERATE(ei, table)
3287      Example_pack(*ei, buf, otherValues);
3288
3289    if (!otherValues) {
3290      otherValues = Py_None;
3291      Py_INCREF(otherValues);
3292    }
3293
3294    return Py_BuildValue("O(ONs#N)O", getExportedFunction("__pickleLoaderExampleTable"),
3295                                      self->ob_type,
3296                                      WrapOrange(table->domain),
3297                                      buf.buf, buf.length(),
3298                                      otherValues,
3299                                      packOrangeDictionary(self));
3300  }
3301}
3302
3303
3304PyObject *__pickleLoaderExampleTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, domain, packed_values, other_values)")
3305{
3306  PyTRY
3307    PyTypeObject *type;
3308    PDomain domain;
3309    char *buf;
3310    int bufSize;
3311    PyObject *otherValues;
3312
3313    if (!PyArg_ParseTuple(args, "OO&s#O:__pickleLoaderExampleTable", &type, cc_Domain, &domain, &buf, &bufSize, &otherValues))
3314      return NULL;
3315
3316    TCharBuffer cbuf(buf);
3317    int otherValuesIndex = 0;
3318
3319    int noOfEx = cbuf.readInt();
3320    TExampleTable *newTable = new TExampleTable(domain);
3321    try {
3322      newTable->reserve(noOfEx);
3323      for(int i = noOfEx; i--;)
3324        Example_unpack(newTable->new_example(), cbuf, otherValues, otherValuesIndex);
3325
3326      return WrapNewOrange(newTable, type);
3327    }
3328    catch (...) {
3329      delete newTable;
3330      throw;
3331    }
3332  PyCATCH
3333}
3334
3335
3336PyObject *__pickleLoaderExampleReferenceTable(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, lockedtable, indices)")
3337{
3338  PyTRY
3339    PyTypeObject *type;
3340    PExampleTable table;
3341    char *buf;
3342    int bufSize;
3343
3344    if (!PyArg_ParseTuple(args, "OO&s#:__pickleLoaderExampleReferenceTable", &type, cc_ExampleTable, &table, &buf, &bufSize))
3345      return NULL;
3346
3347
3348    TCharBuffer cbuf(buf);
3349    int noOfEx = cbuf.readInt();
3350
3351    TExampleTable *newTable = new TExampleTable(table, 1);
3352    try {
3353      newTable->reserve(noOfEx);
3354      for(int i = noOfEx; i--;)
3355        newTable->addExample(table->at(cbuf.readInt()));
3356      return WrapNewOrange(newTable, type);
3357    }
3358    catch (...) {
3359      delete newTable;
3360      throw;
3361    }
3362  PyCATCH
3363}
3364
3365
3366#define EXAMPLE_LOCK(tab) (((tab)->ownsExamples || !(tab)->lock) ? PExampleGenerator(tab) : (tab)->lock)
3367
3368PyObject *ExampleTable_native(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=]) -> examples")
3369{ PyTRY
3370    int natvt=2;
3371    if (args && !PyArg_ParseTuple(args, "|i", &natvt) || ((natvt>=3)))
3372      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
3373
3374    if (natvt<2)
3375      return ExampleGenerator_native(self, args, keywords);
3376
3377    CAST_TO(TExampleTable, table);
3378
3379    PyObject *list=PyList_New(table->numberOfExamples());
3380    Py_ssize_t i=0;
3381    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3382    EITERATE(ei, *table) {
3383      // here we wrap a reference to example, so we must pass a self's wrapper
3384      PyObject *example = Example_FromExampleRef(*ei, lock);
3385      if (!example) {
3386        PyMem_DEL(list);
3387        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3388      }
3389      PyList_SetItem(list, i++, example);
3390    }
3391
3392    return list;
3393  PyCATCH
3394}
3395
3396/*
3397PyTypeObject *gsl_matrixType = NULL;
3398
3399bool load_gsl()
3400{
3401  if (gsl_matrixType)
3402    return true;
3403
3404  PyObject *matrixModule = PyImport_ImportModule("pygsl.matrix");
3405  if (!matrixModule)
3406    return false;
3407
3408  gsl_matrixType = (PyTypeObject *)PyDict_GetItemString(PyModule_GetDict(matrixModule), "matrix");
3409  return gsl_matrixType != NULL;
3410}
3411*/
3412
3413
3414/* Not in .hpp (to be parsed by pyprops) since these only occur in arguments to numpy conversion function */
3415
3416PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Ignore, 0)
3417PYCLASSCONSTANT_INT(ExampleTable, Multinomial_AsOrdinal, 1)
3418PYCLASSCONSTANT_INT(ExampleTable, Multinomial_Error, 2)
3419
3420
3421
3422PyObject *packMatrixTuple(PyObject *X, PyObject *y, PyObject *my, PyObject *w, char *contents)
3423{
3424  int left = (*contents && *contents != '/') ? 1 : 0;
3425
3426  char *cp = strchr(contents, '/');
3427  if (cp)
3428    cp++;
3429
3430  int right = cp ? strlen(cp) : 0;
3431
3432  PyObject *res = PyTuple_New(left + right);
3433  if (left) {
3434    Py_INCREF(X);
3435    PyTuple_SetItem(res, 0, X);
3436  }
3437
3438  if (cp)
3439    for(; *cp; cp++)
3440      if ((*cp == 'c') || (*cp == 'C')) {
3441        Py_INCREF(y);
3442        PyTuple_SetItem(res, left++, y);
3443      }
3444      else if ((*cp == 'w') || (*cp == 'W')) {
3445        Py_INCREF(w);
3446        PyTuple_SetItem(res, left++, w);
3447      }
3448      else {
3449        Py_INCREF(my);
3450        PyTuple_SetItem(res, left++, my);
3451      }
3452
3453  Py_DECREF(X);
3454  Py_DECREF(y);
3455  Py_DECREF(my);
3456  Py_DECREF(w);
3457  return res;
3458}
3459
3460
3461void parseMatrixContents(PExampleGenerator egen, const int &weightID, const char *contents, const int &multiTreatment,
3462                         bool &hasClass, bool &classVector, bool &multiclassVector, bool &weightVector, bool &classIsDiscrete, int &columns,
3463                         vector<bool> &include);
3464
3465
3466inline bool storeNumPyValue(double *&p, const TValue &val, signed char *&m, const PVariable attr, const int &row)
3467{
3468  if (val.isSpecial()) {
3469    if (m) {
3470      *p++ = 0;
3471      *m++ = 1;
3472    }
3473    else {
3474      PyErr_Format(PyExc_TypeError, "value of attribute '%s' in example '%i' is undefined", attr->get_name().c_str(), row);
3475      return false;
3476    }
3477  }
3478
3479  else if (val.varType == TValue::FLOATVAR) {
3480    *p++ = val.floatV;
3481    if (m)
3482      *m++ = 0;
3483  }
3484
3485  else if (val.varType == TValue::INTVAR) {
3486    *p++ = float(val.intV);
3487    if (m)
3488      *m++ = 0;
3489  }
3490
3491  else {
3492    *p++ = ILLEGAL_FLOAT;
3493    if (m)
3494      *m++ = 1;
3495  }
3496
3497  return true;
3498}
3499
3500
3501PyObject *ExampleTable_toNumericOrMA(PyObject *self, PyObject *args, PyObject *keywords, PyObject **module, PyObject **maskedArray = NULL)
3502{
3503  PyTRY
3504    prepareNumeric();
3505    if (!*module || maskedArray && !*maskedArray)
3506      PYERROR(PyExc_ImportError, "cannot import the necessary numeric module for conversion", PYNULL);
3507
3508    // These references are all borrowed
3509    PyObject *moduleDict = PyModule_GetDict(*module);
3510      PyObject *mzeros = PyDict_GetItemString(moduleDict, "zeros");
3511      if (!mzeros)
3512        PYERROR(PyExc_AttributeError, "numeric module has no function 'zeros'", PYNULL);
3513
3514    char *contents = NULL;
3515    int weightID = 0;
3516    int multinomialTreatment = 1;
3517    if (!PyArg_ParseTuple(args, "|sii:ExampleTable.toNumeric", &contents, &weightID, &multinomialTreatment))
3518      return PYNULL;
3519
3520    if (!contents)
3521      contents = "a/cw";
3522
3523    PExampleGenerator egen = PyOrange_AsExampleGenerator(self);
3524
3525    bool hasClass, classVector, weightVector, multiclassVector, classIsDiscrete;
3526    vector<bool> include;
3527    int columns;
3528    parseMatrixContents(egen, weightID, contents, multinomialTreatment,
3529                            hasClass, classVector, multiclassVector, weightVector,
3530                            classIsDiscrete, columns, include);
3531
3532    int rows = egen->numberOfExamples();
3533    PVariable classVar = egen->domain->classVar;
3534
3535    PyObject *X, *y, *w, *my, *mask = NULL, *masky = NULL, *maskmy = NULL;
3536    double *Xp, *yp, *myp, *wp;
3537    signed char *mp = NULL, *mpy = NULL, *mpmy = NULL;
3538    X = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "d");
3539    if (!X)
3540        return PYNULL;
3541    Xp = columns ? (double *)((PyArrayObject *)X)->data : NULL;
3542    if (maskedArray) {
3543        mask = PyObject_CallFunction(mzeros, "(ii)s", rows, columns, "b");
3544        mp = (signed char *)((PyArrayObject *)mask)->data;
3545    }
3546
3547    if (classVector) {
3548      y = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3549      if (!y)
3550        return PYNULL;
3551      yp = (double *)((PyArrayObject *)y)->data;
3552
3553      if (maskedArray) {
3554        masky = PyObject_CallFunction(mzeros, "(i)s", rows, "b");
3555        mpy = (signed char *)((PyArrayObject *)masky)->data;
3556      }
3557    }
3558    else {
3559      y = Py_None;
3560      Py_INCREF(y);
3561      yp = NULL;
3562    }
3563
3564    if (multiclassVector) {
3565      my = PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "d");
3566      if (!my)
3567        return PYNULL;
3568      myp = (double *)((PyArrayObject *)my)->data;
3569
3570      if (maskedArray) {
3571        maskmy= PyObject_CallFunction(mzeros, "(ii)s", rows, egen->domain->classVars->size(), "b");
3572        mpmy = (signed char *)((PyArrayObject *)maskmy)->data;
3573      }
3574    }
3575    else {
3576      my = Py_None;
3577      Py_INCREF(my);
3578      myp = NULL;
3579    }
3580
3581    if (weightVector) {
3582      w = PyObject_CallFunction(mzeros, "(i)s", rows, "d");
3583      if (!w)
3584        return PYNULL;
3585      wp = (double *)((PyArrayObject *)w)->data;
3586    }
3587    else {
3588      w = Py_None;
3589      Py_INCREF(w);
3590      wp = NULL;
3591    }
3592
3593    try {
3594      int row = 0;
3595      TExampleGenerator::iterator ei(egen->begin());
3596      for(; ei; ++ei, row++) {
3597        int col = 0;
3598
3599        /* This is all optimized assuming that each symbol (A, C, W) only appears once.
3600           If it would be common for them to appear more than once, we could cache the
3601           values, but since this is unlikely, caching would only slow down the conversion */
3602        for(const char *cp = contents; *cp && (*cp!='/'); cp++) {
3603          switch (*cp) {
3604            case 'A':
3605            case 'a': {
3606              const TVarList &attributes = egen->domain->attributes.getReference();
3607              TVarList::const_iterator vi(attributes.begin()), ve(attributes.end());
3608              TExample::iterator eei((*ei).begin());
3609              vector<bool>::const_iterator bi(include.begin());
3610              for(; vi != ve; eei++, vi++, bi++)
3611                if (*bi && !storeNumPyValue(Xp, *eei, mp, *vi, row))
3612                  return PYNULL;
3613              break;
3614            }
3615
3616            case 'C':
3617            case 'c':
3618              if (hasClass && !storeNumPyValue(Xp, (*ei).getClass(), mp, classVar, row))
3619                return PYNULL;
3620              break;
3621
3622            case 'M':
3623            case 'm': {
3624              const TVarList &classes = egen->domain->classVars.getReference();
3625              TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3626              TValue *eei = (*ei).values_end;
3627              for(; vi != ve; eei++, vi++)
3628                if (!storeNumPyValue(Xp, *eei, mp, *vi, row))
3629                  return PYNULL;
3630              break;
3631            }
3632
3633            case 'W':
3634            case 'w':
3635              if (weightID)
3636                *Xp++ = WEIGHT(*ei);
3637                if (maskedArray)
3638                  *mp++ = 0;
3639              break;
3640
3641            case '0':
3642              *Xp++ = 0.0;
3643              if (maskedArray)
3644                *mp++ = 0;
3645              break;
3646
3647            case '1':
3648              *Xp++ = 1.0;
3649              if (maskedArray)
3650                *mp++ = 0;
3651              break;
3652          }
3653        }
3654
3655        if (yp && !storeNumPyValue(yp, (*ei).getClass(), mpy, classVar, row))
3656          return PYNULL;
3657
3658        if (wp)
3659          *wp++ = WEIGHT(*ei);
3660
3661        if (myp) {
3662            const TVarList &classes = egen->domain->classVars.getReference();
3663            TVarList::const_iterator vi(classes.begin()), ve(classes.end());
3664            TValue *eei = (*ei).values_end;
3665            for(; vi != ve; eei++, vi++)
3666              if (!storeNumPyValue(myp, *eei, mpmy, *vi, row))
3667                return PYNULL;
3668        }
3669      }
3670
3671      if (maskedArray) {
3672        PyObject *args, *maskedX = NULL, *maskedy = NULL, *maskedmy = NULL;
3673
3674        bool err = false;
3675
3676        if (mask) {
3677          args = Py_BuildValue("OOiOO", X, Py_None, 1, Py_None, mask);
3678          maskedX = PyObject_CallObject(*maskedArray, args);
3679          Py_DECREF(args);
3680          if (!maskedX) {
3681            PyErr_Clear();
3682            args = Py_BuildValue("OOOi", X, mask, Py_None, 1);
3683            maskedX = PyObject_CallObject(*maskedArray, args);
3684            Py_DECREF(args);
3685          }
3686          err = !maskedX;
3687        }
3688
3689        if (!err && masky) {
3690          args = Py_BuildValue("OOiOO", y, Py_None, 1, Py_None, masky);
3691          maskedy = PyObject_CallObject(*maskedArray, args);
3692          Py_DECREF(args);
3693          if (!maskedy) {
3694            PyErr_Clear();
3695            args = Py_BuildValue("OOOi", y, masky, Py_None, 1);
3696            maskedy = PyObject_CallObject(*maskedArray, args);
3697            Py_DECREF(args);
3698          }
3699          err = !maskedy;
3700        }
3701
3702        if (!err && maskmy) {
3703          args = Py_BuildValue("OOiOO", my, Py_None, 1, Py_None, maskmy);
3704          maskedmy = PyObject_CallObject(*maskedArray, args);
3705          Py_DECREF(args);
3706          if (!maskedmy) {
3707            PyErr_Clear();
3708            args = Py_BuildValue("OOOi", my, maskmy, Py_None, 1);
3709            maskedmy = PyObject_CallObject(*maskedArray, args);
3710            Py_DECREF(args);
3711          }
3712          err = !maskedmy;
3713        }
3714
3715        if (err) {
3716          Py_DECREF(X);
3717          Py_DECREF(y);
3718          Py_DECREF(w);
3719          Py_XDECREF(maskedX);
3720          Py_XDECREF(mask);
3721          Py_XDECREF(masky);
3722          Py_XDECREF(maskmy);
3723          return PYNULL;
3724        }
3725
3726        if (mask) {
3727          Py_DECREF(X);
3728          Py_DECREF(mask);
3729          X = maskedX;
3730        }
3731
3732        if (masky) {
3733          Py_DECREF(y);
3734          Py_DECREF(masky);
3735          y = maskedy;
3736        }
3737
3738        if (maskmy) {
3739          Py_DECREF(my);
3740          Py_DECREF(maskmy);
3741          my = maskedmy;
3742        }
3743      }
3744
3745      return packMatrixTuple(X, y, my, w, contents);
3746    }
3747    catch (...) {
3748      Py_DECREF(X);
3749      Py_DECREF(y);
3750      Py_DECREF(w);
3751      Py_XDECREF(mask);
3752      Py_XDECREF(masky);
3753      Py_XDECREF(maskmy);
3754      throw;
3755    }
3756  PyCATCH
3757}
3758
3759
3760PyObject *ExampleTable_toNumeric(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3761{
3762  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric);
3763}
3764
3765
3766PyObject *ExampleTable_toNumericMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3767{
3768  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumeric, &numericMaskedArray);
3769}
3770
3771// this is for compatibility
3772PyObject *ExampleTable_toMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3773{
3774  return ExampleTable_toNumericMA(self, args, keywords);
3775}
3776
3777PyObject *ExampleTable_toNumarray(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3778{
3779  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray);
3780}
3781
3782
3783PyObject *ExampleTable_toNumarrayMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3784{
3785  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumarray, &numarrayMaskedArray);
3786}
3787
3788PyObject *ExampleTable_toNumpy(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3789{
3790  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy);
3791}
3792
3793
3794PyObject *ExampleTable_toNumpyMA(PyObject *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS, "([contents='a/cw'[, weightID=0[, multinomialTreatment=1]]) -> matrix(-ces)")
3795{
3796  return ExampleTable_toNumericOrMA(self, args, keywords, &moduleNumpy, &numpyMaskedArray);
3797}
3798
3799
3800
3801int ExampleTable_nonzero(PyObject *self)
3802{ PyTRY
3803    return SELF_AS(TExampleGenerator).numberOfExamples() ? 1 : 0;
3804  PyCATCH_1
3805}
3806
3807Py_ssize_t ExampleTable_len_sq(PyObject *self)
3808{ PyTRY
3809    return SELF_AS(TExampleGenerator).numberOfExamples();
3810  PyCATCH_1
3811}
3812
3813
3814PyObject *ExampleTable_append(PyObject *self, PyObject *args) PYARGS(METH_O, "(example) -> None")
3815{ PyTRY
3816    CAST_TO(TExampleTable, table)
3817
3818    if (table->ownsExamples) {
3819      if (!convertFromPythonExisting(args, table->new_example())) {
3820        table->delete_last();
3821        return PYNULL;
3822      }
3823    }
3824    else {
3825      if (!PyOrExample_Check(args) || (((TPyExample *)(args))->lock != table->lock))
3826        PYERROR(PyExc_TypeError, "tables containing references to examples can only append examples from the same table", PYNULL);
3827
3828      table->addExample(PyExample_AS_ExampleReference(args));
3829    }
3830    RETURN_NONE;
3831  PyCATCH
3832}
3833
3834PyObject *ExampleTable_extend(PyObject *self, PyObject *args) PYARGS(METH_O, "(examples) -> None")
3835{ PyTRY
3836    CAST_TO(TExampleTable, table)
3837
3838    if (PyOrExampleGenerator_Check(args)) {
3839      PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3840      if (args==self) {
3841        TExampleTable temp(gen, false);
3842        table->addExamples(PExampleGenerator(temp));
3843      }
3844      else {
3845        if (!table->ownsExamples
3846              && (table->lock != gen)
3847              && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3848            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3849        table->addExamples(gen);
3850      }
3851      RETURN_NONE;
3852    }
3853
3854    TExample example(table->domain);
3855    if (PyList_Check(args)) {
3856      Py_ssize_t i, size = PyList_Size(args);
3857
3858      // We won't append until we know we can append all
3859      // (don't want to leave the work half finished)
3860      if (!table->ownsExamples) {
3861        for (i = 0; i<size; i++) {
3862          PyObject *pyex = PyList_GET_ITEM(args, i);
3863          if (!PyOrExample_Check(pyex) || (((TPyExample *)(pyex))->lock != table->lock))
3864            PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", PYNULL);
3865        }
3866      }
3867
3868      for(i = 0; i<size; i++) {
3869        PyObject *pex = PyList_GET_ITEM(args, i);
3870        if (!convertFromPythonExisting(pex, example))
3871          return PYNULL;
3872
3873        table->addExample(example);
3874      }
3875
3876      RETURN_NONE;
3877    }
3878
3879
3880    PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.extend", PYNULL);
3881  PyCATCH
3882}
3883
3884
3885PyObject *ExampleTable_getitem_sq(TPyOrange *self, Py_ssize_t idx)
3886{
3887  PyTRY
3888    CAST_TO(TExampleTable, table);
3889
3890    if (idx<0)
3891      idx += table->numberOfExamples();
3892
3893    if ((idx<0) || (idx>=table->numberOfExamples()))
3894      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
3895
3896    // here we wrap a reference to example, so we must pass self's wrapper
3897    return Example_FromExampleRef((*table)[idx], EXAMPLE_LOCK(PyOrange_AsExampleTable(self)));
3898  PyCATCH
3899}
3900
3901
3902int ExampleTable_setitem_sq(TPyOrange *self, Py_ssize_t idx, PyObject *pex)
3903{
3904  PyTRY
3905    CAST_TO_err(TExampleTable, table, -1);
3906
3907    if (idx>table->numberOfExamples())
3908      PYERROR(PyExc_IndexError, "index out of range", -1);
3909
3910    if (!pex) {
3911      table->erase(idx);
3912      return 0;
3913    }
3914
3915    if (!table->ownsExamples) {
3916      if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock))
3917        PYERROR(PyExc_TypeError, "tables containing references to examples can contain examples from the same table", -1);
3918
3919      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3920      return 0;
3921    }
3922
3923    if (PyOrExample_Check(pex)) {
3924      (*table)[idx] = TExample(table->domain, PyExample_AS_ExampleReference(pex));
3925      return 0;
3926    }
3927
3928    TExample example(table->domain);
3929    if (convertFromPythonExisting(pex, example)) {
3930      (*table)[idx] = example;
3931      return 0;
3932    }
3933
3934    PYERROR(PyExc_TypeError, "invalid parameter type (Example expected)", -1)
3935  PyCATCH_1
3936}
3937
3938
3939PyObject *ExampleTable_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop)
3940{
3941  PyTRY
3942    CAST_TO(TExampleTable, table);
3943
3944    if (stop>table->numberOfExamples())
3945      stop=table->numberOfExamples();
3946
3947    if (start>stop)
3948      start=stop;
3949
3950    PyObject *list=PyList_New(stop-start);
3951    Py_ssize_t i=0;
3952    PExampleGenerator lock = EXAMPLE_LOCK(PyOrange_AsExampleTable(self));
3953    while(start<stop) {
3954      // here we wrap a reference to example, so we must pass a self's wrapper
3955      PyObject *example=Example_FromExampleRef((*table)[start++], lock);
3956      if (!example) {
3957        PyMem_DEL(list);
3958        PYERROR(PyExc_SystemError, "out of memory", PYNULL);
3959      }
3960      PyList_SetItem(list, i++, (PyObject *)example);
3961    }
3962
3963    return list;
3964  PyCATCH
3965}
3966
3967
3968int ExampleTable_setslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop, PyObject *args)
3969{
3970  PyTRY
3971    CAST_TO_err(TExampleTable, table, -1);
3972
3973    if (stop>table->size())
3974      stop = table->size();
3975
3976    if (start>stop)
3977      PYERROR(PyExc_IndexError, "index out of range", -1);
3978
3979    int inspoint = stop;
3980
3981    try {
3982      if (PyOrExampleGenerator_Check(args)) {
3983        PExampleGenerator gen = PyOrange_AsExampleGenerator(args);
3984        if (args==(PyObject *)self) {
3985          TExampleTable tab(gen, false);
3986          EITERATE(ei, tab)
3987            table->insert(inspoint++, *ei);
3988        }
3989        else
3990          if (!table->ownsExamples
3991                && (table->lock != gen)
3992                && (!gen.is_derived_from(TExampleTable) || (table->lock != gen.AS(TExampleTable)->lock)))
3993              PYERROR(PyExc_TypeError, "tables containing references to examples can only contain examples from the same table", -1);
3994          PEITERATE(ei, gen)
3995            table->insert(inspoint++, *ei);
3996      }
3997
3998      else {
3999        TExample example(table->domain);
4000        if (PyList_Check(args)) {
4001          Py_ssize_t size = PyList_Size(args);
4002
4003          for(Py_ssize_t i = 0; i<size; i++) {
4004            PyObject *pex = PyList_GetItem(args, i);
4005
4006            if (table->ownsExamples) {
4007              if (!convertFromPythonExisting(pex, example)) {
4008                table->erase(stop, inspoint);
4009                return -1;
4010              }
4011              table->insert(inspoint++, example);
4012            }
4013            else {
4014              if (!PyOrExample_Check(pex) || (((TPyExample *)(pex))->lock != table->lock)) {
4015                table->erase(stop, inspoint);
4016                PYERROR(PyExc_TypeError, "tables containing references to examples can only extend by examples from the same table", -1);
4017              }
4018              table->insert(inspoint++, PyExample_AS_ExampleReference(pex));
4019            }
4020          }
4021        }
4022        else
4023          PYERROR(PyExc_TypeError, "invalid argument for ExampleTable.__setslice__", -1);
4024      }
4025    }
4026    catch (...) {
4027      table->erase(stop, inspoint);
4028      throw;
4029    }
4030
4031    table->erase(start, stop);
4032
4033    return 0;
4034  PyCATCH_1
4035}
4036
4037
4038PyObject *applyFilterL(PFilter filter, PExampleTable gen)
4039{ if (!filter)
4040    return PYNULL;
4041
4042  PyObject *list=PyList_New(0);
4043  filter->reset();
4044  PExampleGenerator lock = EXAMPLE_LOCK(gen);
4045  PEITERATE(ei, gen)
4046    if (filter->operator()(*ei)) {
4047      PyObject *obj=Example_FromExampleRef(*ei, lock);
4048      PyList_Append(list, obj);
4049      Py_DECREF(obj);
4050    }
4051
4052  return list;
4053}
4054
4055
4056PyObject *applyFilterP(PFilter filter, PExampleTable gen)
4057{ if (!filter)
4058    return PYNULL;
4059
4060  TExampleTable *newTable = mlnew TExampleTable(PExampleGenerator(gen), 1);
4061  PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4062  filter->reset();
4063  PEITERATE(ei, gen)
4064    if (filter->operator()(*ei))
4065      newTable->addExample(*ei);
4066
4067  return WrapOrange(newGen);
4068}
4069
4070
4071PyObject *filterSelectionVectorLow(TFilter &filter, PExampleGenerator egen);
4072
4073PyObject *applyFilterB(PFilter filter, PExampleTable gen)
4074{
4075  return filter ? filterSelectionVectorLow(filter.getReference(), gen) : PYNULL;
4076}
4077
4078
4079PyObject *ExampleTable_get_items_ref(TPyOrange *self, PyObject *pylist)   PYARGS(METH_O, "(indices) -> ExampleTable")
4080{ return multipleSelectLow(self, pylist, true); }
4081
4082
4083PyObject *ExampleTable_selectLow(TPyOrange *self, PyObject *args, PyObject *keywords, const int toList)
4084{
4085  PyTRY
4086    CAST_TO(TExampleTable, eg);
4087    PExampleGenerator weg = PExampleGenerator(PyOrange_AS_Orange(self));
4088    PExampleGenerator lock = EXAMPLE_LOCK(eg);
4089
4090    /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS KEYWORDS ***** */
4091    /* Deprecated: use 'filter' instead */
4092    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4093      switch (toList) {
4094        case 2: return applyFilterB(filter_sameValues(keywords, eg->domain), weg);
4095        case 1: return applyFilterL(filter_sameValues(keywords, eg->domain), weg);
4096        default: return applyFilterP(filter_sameValues(keywords, eg->domain), weg);
4097      }
4098    }
4099
4100    PyObject *mplier;
4101    int index;
4102    if (PyArg_ParseTuple(args, "O|i", &mplier, &index)) {
4103      PyObject *pyneg = keywords ? PyDict_GetItemString(keywords, "negate") : NULL;
4104      bool negate = pyneg && PyObject_IsTrue(pyneg);
4105      bool indexGiven = (PyTuple_Size(args)==2);
4106
4107      /* ***** SELECTION BY PYLIST ****** */
4108      if (PyList_Check(mplier)) {
4109        if (PyList_Size(mplier) != eg->numberOfExamples())
4110          PYERROR(PyExc_IndexError, "example selector of invalid length", PYNULL);
4111
4112        int i = 0;
4113        switch (toList) {
4114
4115          case 1: {
4116            PyObject *list = PyList_New(0);
4117
4118            if (indexGiven)
4119              EITERATE(ei, *eg) {
4120                PyObject *lel = PyList_GetItem(mplier, i++);
4121                if (!PyInt_Check(lel))
4122                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4123
4124                if (negate != (index==PyInt_AsLong(lel))) {
4125                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4126                  PyList_Append(list, pyex);
4127                  Py_DECREF(pyex);
4128                }
4129              }
4130            else
4131              EITERATE(ei, *eg)
4132                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0)) {
4133                  PyObject *pyex = Example_FromExampleRef(*ei, lock);
4134                  PyList_Append(list, pyex);
4135                  Py_DECREF(pyex);
4136                }
4137
4138            return list;
4139          }
4140
4141
4142          // this is a pervesion, but let's support it as a kind of syntactic sugar...
4143          case 2: {
4144            const Py_ssize_t lsize = PyList_Size(mplier);
4145            TBoolList *selection = new TBoolList(lsize);
4146            PBoolList pselection = selection;
4147            TBoolList::iterator si(selection->begin());
4148            if (indexGiven)
4149              for(Py_ssize_t i = 0; i < lsize; i++) {
4150                PyObject *lel = PyList_GetItem(mplier, i);
4151                if (!PyInt_Check(lel))
4152                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4153
4154                *si++ = negate != (index == PyInt_AsLong(lel));
4155              }
4156            else
4157              for(Py_ssize_t i = 0; i < lsize; *si++ = negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0));
4158
4159            return WrapOrange(pselection);
4160          }
4161
4162
4163          default: {
4164            TExampleTable *newTable = mlnew TExampleTable(lock, 1); //locks to weg but does not copy
4165            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4166
4167            if (indexGiven)
4168              EITERATE(ei, *eg) {
4169                PyObject *lel = PyList_GetItem(mplier, i++);
4170                if (!PyInt_Check(lel))
4171                  PYERROR(PyExc_IndexError, "example selector must be an integer index", PYNULL)
4172
4173                if (negate != (index==PyInt_AsLong(lel)))
4174                  newTable->addExample(*ei);
4175              }
4176            else
4177              EITERATE(ei, *eg)
4178                if (negate != (PyObject_IsTrue(PyList_GetItem(mplier, i++)) != 0))
4179                  newTable->addExample(*ei);
4180
4181            return WrapOrange(newGen);
4182          }
4183        }
4184      }
4185
4186      /* ***** SELECTION BY LONGLIST ****** */
4187      else if (PyOrLongList_Check(mplier)) {
4188        PLongList llist = PyOrange_AsLongList(mplier);
4189        if (int(llist->size()) != eg->numberOfExamples())
4190          PYERROR(PyExc_IndexError, "select: invalid list size", PYNULL)
4191
4192        TLongList::iterator lli(llist->begin()), lle(llist->end());
4193        TExampleIterator ei = eg->begin();
4194
4195        switch (toList) {
4196          case 1: {
4197            PyObject *list = PyList_New(0);
4198            for(; ei && (lli!=lle); ++ei, lli++)
4199              if (negate != (indexGiven ? (*lli==index) : (*lli!=0))) {
4200                PyObject *pyex = Example_FromExampleRef(*ei, lock);
4201                PyList_Append(list, pyex);
4202                Py_DECREF(pyex);
4203              }
4204            return list;
4205          }
4206
4207          case 2: {
4208            TBoolList *selection = new TBoolList(llist->size());
4209            PBoolList pselection = selection;
4210            for(TBoolList::iterator si(selection->begin()); lli != lle; *si++ = negate != (indexGiven ? (*lli++ == index) : (*lli++ != 0)));
4211
4212            return WrapOrange(pselection);
4213          }
4214
4215          default: {
4216            TExampleTable *newTable = mlnew TExampleTable(lock, 1);
4217            PExampleGenerator newGen(newTable); // ensure it gets deleted in case of error
4218
4219            for(;ei && (lli!=lle); ++ei, lli++)
4220              if (negate != (indexGiven ? (*lli==index) : (*lli!=0)))
4221                newTable->addExample(*ei);
4222
4223            return WrapOrange(newGen);
4224          }
4225        }
4226      }
4227
4228      PyErr_Clear();
4229
4230
4231      /* ***** SELECTING BY VALUES OF ATTRIBUTES GIVEN AS DICTIONARY ***** */
4232      /* Deprecated: use method 'filter' instead. */
4233      if (PyDict_Check(mplier))
4234        switch (toList) {
4235          case 2: return applyFilterB(filter_sameValues(mplier, eg->domain), weg);
4236          case 1: return applyFilterL(filter_sameValues(mplier, eg->domain), weg);
4237          default: return applyFilterP(filter_sameValues(mplier, eg->domain), weg);
4238        }
4239
4240      else if (PyOrFilter_Check(mplier))
4241        switch (toList) {
4242          case 2: return applyFilterB(PyOrange_AsFilter(mplier), weg);
4243          case 1: return applyFilterL(PyOrange_AsFilter(mplier), weg);
4244          default: return applyFilterP(PyOrange_AsFilter(mplier), weg);
4245        }
4246    }
4247
4248  PYERROR(PyExc_TypeError, "invalid example selector type", PYNULL);
4249  PyCATCH
4250}
4251
4252
4253PyObject *ExampleTable_select_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4254{ PyTRY
4255    return ExampleTable_selectLow(self, args, keywords, 1);
4256  PyCATCH
4257}
4258
4259
4260PyObject *ExampleTable_select_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4261{ PyTRY
4262    return ExampleTable_selectLow(self, args, keywords, 0);
4263  PyCATCH
4264}
4265
4266
4267PyObject *ExampleTable_select_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "see the manual for help")
4268{ PyTRY
4269    return ExampleTable_selectLow(self, args, keywords, 2);
4270  PyCATCH
4271}
4272
4273
4274PyObject *ExampleTable_filter_list(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4275{
4276  PyTRY
4277    CAST_TO(TExampleGenerator, eg);
4278    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4279
4280    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4281      return applyFilterL(filter_sameValues(keywords, eg->domain, keywords), weg);
4282    }
4283
4284    if (PyTuple_Size(args)==1) {
4285      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4286
4287      if (PyDict_Check(arg))
4288        return applyFilterL(filter_sameValues(arg, eg->domain, keywords), weg);
4289
4290      if (PyOrFilter_Check(arg))
4291          return applyFilterL(PyOrange_AsFilter(arg), weg);
4292    }
4293
4294    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_list expects a list of conditions or orange.Filter", PYNULL)
4295  PyCATCH
4296}
4297
4298
4299PyObject *ExampleTable_filter_ref(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4300{
4301  PyTRY
4302    CAST_TO(TExampleGenerator, eg);
4303    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4304
4305    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4306      return applyFilterP(filter_sameValues(keywords, eg->domain, keywords), weg);
4307    }
4308
4309    if (PyTuple_Size(args)==1) {
4310      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4311
4312      if (PyDict_Check(arg))
4313        return applyFilterP(filter_sameValues(arg, eg->domain, keywords), weg);
4314
4315      if (PyOrFilter_Check(arg))
4316          return applyFilterP(PyOrange_AsFilter(arg), weg);
4317    }
4318
4319    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_ref expects a list of conditions or orange.Filter", PYNULL)
4320  PyCATCH
4321}
4322
4323
4324PyObject *ExampleTable_filter_bool(TPyOrange *self, PyObject *args, PyObject *keywords) PYARGS(METH_VARARGS | METH_KEYWORDS, "(list-of-attribute-conditions | filter)")
4325{
4326  PyTRY
4327    CAST_TO(TExampleGenerator, eg);
4328    PExampleGenerator weg = PyOrange_AsExampleGenerator(self);
4329
4330    if (!PyTuple_Size(args) && NOT_EMPTY(keywords)) {
4331      return applyFilterB(filter_sameValues(keywords, eg->domain, keywords), weg);
4332    }
4333
4334    if (PyTuple_Size(args)==1) {
4335      PyObject *arg = PyTuple_GET_ITEM(args, 0);
4336
4337      if (PyDict_Check(arg))
4338        return applyFilterB(filter_sameValues(arg, eg->domain, keywords), weg);
4339
4340      if (PyOrFilter_Check(arg))
4341          return applyFilterB(PyOrange_AsFilter(arg), weg);
4342    }
4343
4344    PYERROR(PyExc_AttributeError, "ExampleGenerator.filter_bool expects a list of conditions or orange.Filter", PYNULL)
4345  PyCATCH
4346}
4347
4348
4349PyObject *ExampleTable_random_example(TPyOrange *self) PYARGS(0, "() -> Example")
4350{ PyTRY
4351    CAST_TO(TExampleTable, table);
4352    TExample example(table->domain);
4353    table->randomExample(example);
4354    return Example_FromExampleCopyRef(example);
4355  PyCATCH
4356}
4357
4358
4359PyObject *ExampleTable_removeDuplicates(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([weightID=0]]) -> None")
4360{ PyTRY
4361    if (PyTuple_Size(args) > 1)
4362      PYERROR(PyExc_AttributeError, "at most one argument (weight) expected", PYNULL);
4363
4364    CAST_TO(TExampleTable, table);
4365
4366    int weightID = 0;
4367    if (PyTuple_Size(args) && !weightFromArg_byDomain(PyTuple_GET_ITEM(args, 0), table->domain, weightID))
4368      return PYNULL;
4369
4370    table->removeDuplicates(weightID);
4371    RETURN_NONE;
4372  PyCATCH
4373}
4374
4375
4376PyObject *ExampleTable_shuffle(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None")
4377{
4378  PyTRY
4379    SELF_AS(TExampleTable).shuffle();
4380    RETURN_NONE;
4381  PyCATCH
4382}
4383
4384PyObject *ExampleTable_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> None")
4385{ PyTRY
4386    CAST_TO(TExampleTable, table);
4387
4388    if (!args || !PyTuple_Size(args)) {
4389      table->sort();
4390      RETURN_NONE;
4391    }
4392
4393    PyObject *alist = PyTuple_GET_ITEM(args, 0);
4394    /* If the first argument is nor list nor tuple, the whole argument is taken as a list
4395       i.e., data.sort("age", "prescr") is interpreted the same as data.sort(["age", "prescr"])
4396       All references are borrowed. */
4397    if ((PyTuple_Size(args) > 1) || (!PyList_Check(alist) && !PyTuple_Check(alist)))
4398      alist = args;
4399
4400    TVarList attributes;
4401    if (varListFromDomain(alist, table->domain, attributes, true, true)) {
4402      vector<int> order;
4403      for(TVarList::reverse_iterator vi(attributes.rbegin()), ve(attributes.rend()); vi!=ve; vi++)
4404        order.push_back(table->domain->getVarNum(*vi));
4405      table->sort(order);
4406      RETURN_NONE;
4407    }
4408
4409    PYERROR(PyExc_TypeError, "invalid arguments (none, or a list of attributes expected)", PYNULL);
4410
4411  PyCATCH
4412}
4413
4414
4415PyObject *ExampleTable_addMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id[, Value=1.0]) -> None")
4416{ PyTRY
4417    CAST_TO(TExampleTable, table);
4418
4419    PyObject *pyid;
4420    PyObject *pyvalue=PYNULL;
4421    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4422      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4423
4424    int id;
4425    PVariable metavariable;
4426    if (PyInt_Check(pyid)) {
4427      id = PyInt_AsLong(pyid);
4428      metavariable = table->domain->getMetaVar(id, false);
4429    }
4430    else if (PyString_Check(pyid)) {
4431      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4432      metavariable = table->domain->getMetaVar(id, false);
4433    }
4434    else if (PyOrVariable_Check(pyid)) {
4435      metavariable = PyOrange_AsVariable(pyid);
4436      id = table->domain->getMetaNum(metavariable);
4437    }
4438
4439    TValue value;
4440    if (!pyvalue)
4441      if (metavariable && metavariable->varType != TValue::FLOATVAR)
4442        value = metavariable->DK();
4443      else
4444        value = TValue(float(1.0));
4445    else if (!convertFromPython(pyvalue, value, metavariable))
4446      PYERROR(PyExc_AttributeError, "invalid value argument", PYNULL);
4447
4448    table->addMetaAttribute(id, value);
4449
4450    RETURN_NONE;
4451  PyCATCH
4452}
4453
4454
4455PyObject *ExampleTable_removeMetaAttribute(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(id) -> None")
4456{ PyTRY
4457    CAST_TO(TExampleTable, table);
4458
4459    PyObject *pyid;
4460    PyObject *pyvalue=PYNULL;
4461    if (!PyArg_ParseTuple(args, "O|O", &pyid, &pyvalue))
4462      PYERROR(PyExc_AttributeError, "invalid arguments", PYNULL);
4463
4464    int id;
4465    if (PyInt_Check(pyid))
4466      id = PyInt_AsLong(pyid);
4467    else if (PyString_Check(pyid))
4468      id = table->domain->getMetaNum(string(PyString_AsString(pyid)));
4469    else if (PyOrVariable_Check(pyid))
4470      id = table->domain->getMetaNum(PyOrange_AsVariable(pyid));
4471
4472    table->removeMetaAttribute(id);
4473
4474    RETURN_NONE;
4475  PyCATCH
4476}
4477
4478
4479PyObject *ExampleTable_changeDomain(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(Domain) -> None")
4480{ PyTRY
4481    CAST_TO(TExampleTable, table);
4482    if (!table->ownsExamples)
4483      PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4484
4485    PDomain domain;
4486    if (!PyArg_ParseTuple(args, "O&", cc_Domain, &domain))
4487      PYERROR(PyExc_AttributeError, "domain argument expected", PYNULL);
4488
4489    table->changeDomain(domain);
4490    RETURN_NONE;
4491  PyCATCH
4492}
4493
4494PyObject *ExampleTable_pickClass(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Variable | name) -> None")
4495{
4496    PyTRY
4497        CAST_TO(TExampleTable, table);
4498        if (!table->ownsExamples) {
4499            PYERROR(PyExc_TypeError, "tables containing references to examples cannot change domain", PYNULL);
4500        }
4501        PVariable newClass;
4502        if (PyString_Check(obj)) {
4503            const char *attr = PyString_AS_STRING(obj);
4504            TVarList::const_iterator mci(table->domain->classVars->begin()), mce(table->domain->classVars->end());
4505            for(; (mci != mce) && ((*mci)->get_name() != attr); mci++);
4506            if (mci == mce) {
4507                PYERROR(PyExc_TypeError, "table does not have multiple classes", PYNULL);
4508            }
4509            newClass = *mci;
4510        }
4511        if (PyOrVariable_Check(obj)) {
4512            newClass = PyOrange_AsVariable(obj);
4513        }
4514        else if (obj != Py_None) {
4515            PYERROR(PyExc_TypeError, "class should be given as Variable, name or None", PYNULL);
4516        }
4517        table->pickClass(newClass);
4518        RETURN_NONE;
4519    PyCATCH;
4520}
4521
4522
4523
4524PyObject *ExampleTable_hasMissingValues(TPyOrange *self) PYARGS(0, "() -> bool")
4525{
4526  PyTRY
4527    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissing());
4528  PyCATCH
4529}
4530
4531
4532PyObject *ExampleTable_hasMissingClasses(TPyOrange *self) PYARGS(0, "() -> bool")
4533{
4534  PyTRY
4535    return PyInt_FromLong(SELF_AS(TExampleTable).hasMissingClass());
4536  PyCATCH
4537}
4538/* ************ TRANSFORMVALUE ************ */
4539
4540#include "transval.hpp"
4541BASED_ON(TransformValue, Orange)
4542
4543PyObject *TransformValue_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange, "<abstract>")
4544{ if (type == (PyTypeObject *)&PyOrTransformValue_Type)
4545    return setCallbackFunction(WrapNewOrange(mlnew TTransformValue_Python(), type), args);
4546  else
4547    return WrapNewOrange(mlnew TTransformValue_Python(), type);
4548}
4549
4550
4551PyObject *TransformValue__reduce__(PyObject *self)
4552{
4553  return callbackReduce(self, PyOrTransformValue_Type);
4554}
4555
4556
4557PyObject *TransformValue_call(PyObject *self, PyObject *args, PyObject *keywords) PYDOC("(value) -> Value")
4558{ PyTRY
4559    NO_KEYWORDS
4560
4561    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrTransformValue_Type) {
4562      PyErr_Format(PyExc_SystemError, "TransformValue.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
4563      return PYNULL;
4564    }
4565
4566    CAST_TO(TTransformValue, tv)
4567
4568    TPyValue *value;
4569    if (!convertFromPython(args, value))
4570      return PYNULL;
4571
4572    tv->transform(value->value);
4573    value->variable=PVariable();
4574    return (PyObject *)value;
4575  PyCATCH
4576}
4577
4578
4579/* ************ DISTRIBUTION ************ */
4580
4581#include "distvars.hpp"
4582
4583PyObject *convertToPythonNative(const TDiscDistribution &disc)
4584{ int e = disc.size();
4585  PyObject *pylist = PyList_New(e);
4586  for (Py_ssize_t i = 0; i<e; i++)
4587    PyList_SetItem(pylist, i, PyFloat_FromDouble((double)(disc[i])));
4588  return pylist;
4589}
4590
4591PyObject *convertToPythonNative(const TContDistribution &cont)
4592{ PyObject *pydict = PyDict_New();
4593  const_ITERATE(TContDistribution, ci, cont) {
4594    PyObject *key = PyFloat_FromDouble((double)((*ci).first));
4595    PyObject *val = PyFloat_FromDouble((double)((*ci).second));
4596    PyDict_SetItem(pydict, key, val);
4597    Py_DECREF(key);
4598    Py_DECREF(val);
4599  }
4600  return pydict;
4601}
4602
4603
4604bool convertFromPython(PyObject *pylist, TDiscDistribution &disc)
4605{
4606  if (!PyList_Check(pylist))
4607    PYERROR(PyExc_TypeError, "list expected", false);
4608
4609  disc.clear();
4610  float d;
4611  for(Py_ssize_t i = 0, e = PyList_Size(pylist); i!=e; i++) {
4612    if (!PyNumber_ToFloat(PyList_GET_ITEM(pylist, i), d))
4613      PYERROR(PyExc_TypeError, "non-number in DiscDistribution as list", false);
4614    disc.set(TValue((int)i), d);
4615  }
4616
4617  return true;
4618}
4619
4620
4621PyObject *convertToPythonNative(const TDistribution &dist, int)
4622{ const TDiscDistribution *disc = dynamic_cast<const TDiscDistribution *>(&dist);
4623  if (disc)
4624    return convertToPythonNative(*disc);
4625
4626  const TContDistribution *cont = dynamic_cast<const TContDistribution *>(&dist);
4627  if (cont)
4628    return convertToPythonNative(*cont);
4629
4630  PYERROR(PyExc_TypeError, "cannot convert to native python object", PYNULL);
4631}
4632
4633
4634/* Class Distribution has a constructor, but it constructs an instance of either DiscDistribution
4635   or ContDistribution. Class Distribution is thus essentially abstract for Python, although it has
4636   a constructor. */
4637
4638NO_PICKLE(Distribution)
4639
4640PyObject *Distribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(SomeValue - Orange.statistics.distribution.Distribution, "(attribute[, examples[, weightID]])")
4641{
4642  PyTRY
4643    PExampleGenerator gen;
4644    PyObject *pyvar;
4645    int weightID = 0;
4646    if (!PyArg_ParseTuple(args, "O|O&O&:Distribution.new", &pyvar, &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID))
4647      return PYNULL;
4648
4649    TDistribution *dist;
4650
4651    if (!gen) {
4652      if (PyOrVariable_Check(pyvar))
4653        dist = TDistribution::create(PyOrange_AsVariable(pyvar));
4654      else if (PyList_Check(pyvar)) {
4655        TDiscDistribution *ddist = mlnew TDiscDistribution();
4656        if (!convertFromPython(pyvar, *ddist)) {
4657          mldelete ddist;
4658          raiseError("invalid arguments");
4659        }
4660        else
4661          dist = ddist;
4662      }
4663      else
4664        raiseError("invalid arguments");
4665    }
4666    else {
4667      if (PyOrVariable_Check(pyvar))
4668        dist = TDistribution::fromGenerator(gen, PyOrange_AsVariable(pyvar), weightID);
4669      else {
4670        PVariable var = varFromArg_byDomain(pyvar, gen->domain, false);
4671        if (!var)
4672          return PYNULL;
4673
4674        dist = TDistribution::fromGenerator(gen, var, weightID);
4675      }
4676    }
4677
4678    /* We need to override the type (don't want to lie it's Distribution).
4679       The exception is if another type is prescribed. */
4680    return type==(PyTypeObject *)(&PyOrDistribution_Type) ? WrapOrange(PDistribution(dist)) : WrapNewOrange(dist, type);
4681  PyCATCH
4682}
4683
4684
4685PyObject *Distribution_native(PyObject *self, PyObject *) PYARGS(0, "() -> list | dictionary")
4686{
4687  PyTRY
4688    return convertToPythonNative(*PyOrange_AS_Orange(self).AS(TDistribution), 1);
4689  PyCATCH
4690}
4691
4692
4693TDiscDistribution *getDiscDistribution(PyObject *self)
4694{ TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4695  if (!disc)
4696    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected DiscDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4697  return disc;
4698}
4699
4700
4701TContDistribution *getContDistribution(PyObject *self)
4702{ TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4703  if (!cont)
4704    PyErr_Format(PyExc_TypeError, "invalid distribution type (expected ContDistribution, got '%s')", TYPENAME(typeid(PyOrange_AS_Orange(self).getReference())));
4705  return cont;
4706}
4707
4708
4709
4710float *Distribution_getItemRef(PyObject *self, PyObject *index, float *float_idx=NULL)
4711{
4712  TDiscDistribution *disc = PyOrange_AS_Orange(self).AS(TDiscDistribution);
4713  if (disc) {
4714    int ind=-1;
4715    if (PyInt_Check(index))
4716      ind = (int)PyInt_AsLong(index);
4717    else {
4718      if (!disc->variable)
4719        PYERROR(PyExc_SystemError, "invalid distribution (no variable)", (float *)NULL);
4720      TValue val;
4721      if (convertFromPython(index, val, disc->variable) && !val.isSpecial())
4722        ind=int(val);
4723    }
4724
4725    if (ind<0)
4726      PYERROR(PyExc_IndexError, "invalid index for distribution", (float *)NULL);
4727
4728    if (ind<int(disc->size()))
4729      return &disc->at(ind);
4730
4731    PyErr_Format(PyExc_IndexError, "index %i is out of range (0-%i)", ind, disc->size()-1);
4732    return (float *)NULL;
4733  }
4734
4735  TContDistribution *cont = PyOrange_AS_Orange(self).AS(TContDistribution);
4736  if (cont) {
4737    float ind;
4738    if (PyNumber_ToFloat(index, ind)) {
4739      if (float_idx)
4740        *float_idx = ind;
4741    }
4742    else {
4743      TValue val;
4744      if (convertFromPython(index, val, cont->variable) && !val.isSpecial()) {
4745        ind = float(val);
4746        if (float_idx)
4747          *float_idx = ind;
4748      }
4749      else
4750        PYERROR(PyExc_IndexError, "invalid index type (float expected)", NULL);
4751    }
4752
4753    TContDistribution::iterator mi=cont->find(ind);
4754    if (mi!=cont->end())
4755      return &(*mi).second;
4756  }
4757
4758  PYERROR(PyExc_IndexError, "invalid index", (float *)NULL);
4759}
4760
4761
4762PyObject *Distribution_getitem(PyObject *self, PyObject *index)
4763{ PyTRY
4764    float *prob=Distribution_getItemRef(self, index);
4765    return prob ? PyFloat_FromDouble(*prob) : PYNULL;
4766  PyCATCH
4767}
4768
4769
4770int Distribution_setitem(PyObject *self, PyObject *index, PyObject *item)
4771{ PyTRY
4772    PyObject *flt = PyNumber_Float(item);
4773    if (!flt)
4774      PYERROR(PyExc_TypeError, "float expected", -1);
4775
4776    float val=(float)PyFloat_AsDouble(flt);
4777    Py_DECREF(flt);
4778
4779    if (PyOrValue_Check(index)) {
4780      SELF_AS(TDistribution).set(PyValue_AS_Value(index), val);
4781      return 0;
4782    }
4783
4784    float *prob = Distribution_getItemRef(self, index);
4785    if (!prob)
4786      return -1;
4787
4788    *prob = val;
4789    return 0;
4790  PyCATCH_1
4791}
4792
4793
4794string convertToString(const PDistribution &distribution)
4795{
4796  const TDiscDistribution *disc = distribution.AS(TDiscDistribution);
4797  if (disc) {
4798    string res = "<";
4799    char buf[128];
4800    const_PITERATE(TDiscDistribution, di, disc) {
4801      if (res.size()>1)
4802        res += ", ";
4803      sprintf(buf, "%.3f", *di);
4804      res += buf;
4805    }
4806    return res+">";
4807  }
4808
4809  const TContDistribution *cont = distribution.AS(TContDistribution);
4810  if (cont) {
4811    string res = "<";
4812    char buf[128];
4813    const_PITERATE(TContDistribution, di, cont) {
4814      if (res.size()>1)
4815        res += ", ";
4816      sprintf(buf, "%.3f: %.3f", (*di).first, (*di).second);
4817      res += buf;
4818    }
4819    return res+">";
4820  }
4821
4822  raiseErrorWho("convertToString(PDistribution)", "invalid distribution");
4823  return string();
4824}
4825
4826
4827PyObject *Distribution_str(PyObject *self)
4828{ PyTRY
4829    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "str", "repr");
4830    if (result)
4831      return result;
4832
4833    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4834  PyCATCH
4835}
4836
4837
4838PyObject *Distribution_repr(PyObject *self)
4839{ PyTRY
4840    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "repr", "str");
4841    if (result)
4842      return result;
4843
4844    return PyString_FromString(convertToString(PyOrange_AsDistribution(self)).c_str());
4845  PyCATCH
4846}
4847
4848
4849PyObject *Distribution_normalize(PyObject *self) PYARGS(0, "() -> None")
4850{ PyTRY
4851    SELF_AS(TDistribution).normalize();
4852    RETURN_NONE;
4853  PyCATCH
4854}
4855
4856
4857PyObject *Distribution_modus(PyObject *self) PYARGS(0, "() -> Value")
4858{ PyTRY
4859    CAST_TO(TDistribution, dist)
4860    return Value_FromVariableValue(dist->variable, dist->highestProbValue());
4861  PyCATCH
4862}
4863
4864
4865PyObject *Distribution_random(PyObject *self) PYARGS(0, "() -> Value")
4866{ PyTRY
4867    CAST_TO(TDistribution, dist)
4868    return Value_FromVariableValue(dist->variable, dist->randomValue());
4869  PyCATCH
4870}
4871
4872
4873
4874PDiscDistribution list2discdistr(PyObject *args, PyTypeObject *type = NULL)
4875{
4876  TDiscDistribution *udist = mlnew TDiscDistribution();
4877  PDiscDistribution disc = type ? PDistribution(udist) : PDistribution(udist, type);
4878  for(Py_ssize_t i = 0, e = PyList_Size(args); i<e; i++) {
4879    PyObject *flt = PyNumber_Float(PyList_GetItem(args, i));
4880    if (!flt) {
4881      PyErr_Format(PyExc_TypeError, "invalid element at index %i (float expected)", i);
4882      return PDiscDistribution();
4883    }
4884    udist->addint((int)i, (float)PyFloat_AsDouble(flt));
4885    Py_DECREF(flt);
4886  }
4887
4888  return disc;
4889}
4890
4891
4892PyObject *DiscDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Discrete, "[list of floats] | DiscDistribution")
4893{ PyTRY {
4894    if (!PyTuple_Size(targs)) {
4895      return WrapNewOrange(mlnew TDiscDistribution(), type);
4896    }
4897
4898    if (PyTuple_Size(targs)==1) {
4899      PyObject *args = PyTuple_GetItem(targs, 0);
4900
4901      if (PyList_Check(args)) {
4902        PDiscDistribution disc = list2discdistr(args, type);
4903        if (disc)
4904          return WrapOrange(disc);
4905      }
4906
4907      else if (PyOrDiscDistribution_Check(args)) {
4908        Py_INCREF(args);
4909        return args;
4910      }
4911
4912      else if (PyOrEnumVariable_Check(args))
4913        return WrapNewOrange(mlnew TDiscDistribution(PyOrange_AsVariable(args)), type);
4914    }
4915
4916    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
4917  }
4918  PyCATCH;
4919}
4920
4921
4922PyObject *DiscDistribution__reduce__(PyObject *self)
4923{
4924  PyTRY
4925    TDiscDistribution *disc = getDiscDistribution(self);
4926    TCharBuffer buf(sizeof(float)*(disc->size()+2));
4927    buf.writeFloatVector(disc->distribution);
4928
4929    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderDiscDistribution"),
4930                                    self->ob_type,
4931                                    buf.buf, buf.length(),
4932                                    packOrangeDictionary(self));
4933  PyCATCH
4934}
4935
4936
4937PyObject *__pickleLoaderDiscDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
4938{
4939  PyTRY
4940    PyTypeObject *type;
4941    char *buf;
4942    int bufSize;
4943    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &buf, &bufSize))
4944      return PYNULL;
4945
4946    const int &size = (int &)*buf;
4947    buf += sizeof(int);
4948
4949    return WrapNewOrange(new TDiscDistribution((float *)buf, size), type);
4950  PyCATCH
4951}
4952
4953
4954int pt_DiscDistribution(PyObject *args, void *dist)
4955{ if (PyOrDiscDistribution_Check(args)) {
4956    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4957    return 1;
4958  }
4959  else if (PyList_Check(args)) {
4960    *(PDiscDistribution *)(dist) = PyOrange_AsDiscDistribution(args);
4961    if (dist)
4962      return 1;
4963  }
4964
4965  PYERROR(PyExc_TypeError, "invalid discrete distribution", 0)
4966}
4967
4968
4969PyObject *DiscDistribution_getitem_sq(PyObject *self, Py_ssize_t ind)
4970{
4971  PyTRY
4972    TDiscDistribution *disc = getDiscDistribution(self);
4973    if (!disc)
4974      return PYNULL;
4975
4976    if ((ind<0) || (ind>=disc->size()))
4977      PYERROR(PyExc_IndexError, "index out of range", PYNULL);
4978
4979    return PyFloat_FromDouble(double(disc->at(ind)));
4980  PyCATCH
4981}
4982
4983
4984Py_ssize_t DiscDistribution_len(PyObject *self)
4985{ PyTRY
4986    TDiscDistribution *disc = getDiscDistribution(self);
4987    return disc ? disc->size() : -1;
4988  PyCATCH_1
4989}
4990
4991
4992PyObject *DiscDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
4993{ PyTRY
4994    TDiscDistribution *disc = getDiscDistribution(self);
4995    if (!disc)
4996      return PYNULL;
4997
4998    if (!disc->variable)
4999      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
5000
5001    PyObject *nl=PyList_New(disc->variable->noOfValues());
5002    Py_ssize_t i=0;
5003    PStringList vals=disc->variable.AS(TEnumVariable)->values;
5004    PITERATE(TStringList, ii, vals)
5005      PyList_SetItem(nl, i++, PyString_FromString((*ii).c_str()));
5006    return nl;
5007  PyCATCH
5008}
5009
5010
5011PyObject *DiscDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
5012{ PyTRY
5013    TDiscDistribution *disc = getDiscDistribution(self);
5014    if (!disc)
5015      return PYNULL;
5016
5017    if (!disc->variable)
5018      PYERROR(PyExc_TypeError, "invalid distribution (no variable)", PYNULL);
5019
5020    PyObject *nl=PyList_New(disc->variable->noOfValues());
5021    TDiscDistribution::const_iterator ci(disc->begin());
5022    Py_ssize_t i=0;
5023    PStringList vals=disc->variable.AS(TEnumVariable)->values;
5024    PITERATE(TStringList, ii, vals)
5025      PyList_SetItem(nl, i++, Py_BuildValue("sf", (*ii).c_str(), *(ci++)));
5026    return nl;
5027  PyCATCH
5028}
5029
5030
5031PyObject *DiscDistribution_values(PyObject *self) PYARGS(0, "() -> list")
5032{ PyTRY
5033    TDiscDistribution *disc = getDiscDistribution(self);
5034    if (!disc)
5035      return PYNULL;
5036
5037    PyObject *nl = PyList_New(disc->size());
5038    Py_ssize_t i = 0;
5039    const_PITERATE(TDiscDistribution, ci, disc)
5040      PyList_SetItem(nl, i++, PyFloat_FromDouble(*ci));
5041    return nl;
5042  PyCATCH
5043}
5044
5045
5046PyObject *DiscDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5047{ PyTRY
5048    CAST_TO(TDiscDistribution, dist)
5049
5050    PyObject *index;
5051    float weight = 1.0;
5052    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5053      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5054
5055    if (PyInt_Check(index)) {
5056      dist->addint(int(PyInt_AsLong(index)), weight);
5057      RETURN_NONE;
5058    }
5059
5060    TValue val;
5061    if (!dist->variable || !convertFromPython(index, val, dist->variable))
5062      PYERROR(PyExc_TypeError, "DiscDistriubtion.add: cannot convert the arguments to a Value", PYNULL);
5063
5064    dist->add(val, weight);
5065    RETURN_NONE;
5066  PyCATCH;
5067}
5068
5069
5070PyObject *ContDistribution_new(PyTypeObject *type, PyObject *targs, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Continuous, "[dist of float:float] | DiscDistribution")
5071{ PyTRY {
5072
5073    if (!PyTuple_Size(targs))
5074      return WrapNewOrange(mlnew TContDistribution(), type);
5075
5076    if (PyTuple_Size(targs) == 1) {
5077      PyObject *args = PyTuple_GetItem(targs, 0);
5078
5079      if (PyDict_Check(args)) {
5080        TContDistribution *udist = mlnew TContDistribution();
5081        PContDistribution cont = PDistribution(udist);
5082        PyObject *key, *value;
5083        Py_ssize_t pos = 0;
5084        while (PyDict_Next(args, &pos, &key, &value)) {
5085          PyObject *flt = PyNumber_Float(key);
5086          if (!flt) {
5087            PyErr_Format(PyExc_TypeError, "invalid key at index %i (float expected)", pos);
5088            return false;
5089          }
5090          float ind = (float) PyFloat_AsDouble(flt);
5091          Py_DECREF(flt);
5092
5093          flt = PyNumber_Float(value);
5094          if (!flt) {
5095            PyErr_Format(PyExc_TypeError, "invalid value at index %i (float expected)", pos);
5096            return false;
5097          }
5098
5099          udist->addfloat(ind, (float)PyFloat_AsDouble(flt));
5100          Py_DECREF(flt);
5101        }
5102
5103        return WrapOrange(cont);
5104      }
5105
5106      else if (PyOrDistribution_Check(args)) {
5107        Py_INCREF(args);
5108        return args;
5109      }
5110
5111      else if (PyOrFloatVariable_Check(args))
5112        return WrapNewOrange(mlnew TContDistribution(PyOrange_AsVariable(args)), type);
5113    }
5114
5115    PYERROR(PyExc_TypeError, "invalid arguments for distribution constructor", PYNULL);
5116
5117  }
5118  PyCATCH;
5119}
5120
5121
5122PyObject *ContDistribution__reduce__(PyObject *self)
5123{
5124  PyTRY
5125    TContDistribution *cont = getContDistribution(self);
5126    TCharBuffer buf(sizeof(float) * 2 * (cont->size()  +  5));
5127
5128    buf.writeInt(cont->size());
5129    PITERATE(TContDistribution, ci, cont) {
5130      buf.writeFloat((*ci).first);
5131      buf.writeFloat((*ci).second);
5132    }
5133
5134    buf.writeFloat(cont->sum);
5135    buf.writeFloat(cont->sum2);
5136
5137    return Py_BuildValue("O(Os#)N", getExportedFunction("__pickleLoaderContDistribution"),
5138                                    self->ob_type,
5139                                    buf.buf, buf.length(),
5140                                    packOrangeDictionary(self));
5141  PyCATCH
5142}
5143
5144
5145PyObject *__pickleLoaderContDistribution(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(type, packed_distribution)")
5146{
5147  PyTRY
5148    PyTypeObject *type;
5149    char *pbuf;
5150    int bufSize;
5151    if (!PyArg_ParseTuple(args, "Os#:__pickleLoadDiscDistribution", &type, &pbuf, &bufSize))
5152      return PYNULL;
5153
5154    TContDistribution *cdi = new TContDistribution();
5155
5156    TCharBuffer buf(pbuf);
5157    for(int size = buf.readInt(); size--; ) {
5158      // cannot call buf.readFloat() in the make_pair call since we're not sure about the
5159      // order in which the arguments are evaluated
5160      const float p1 = buf.readFloat();
5161      const float p2 = buf.readFloat();
5162      cdi->insert(cdi->end(), make_pair(p1, p2));
5163    }
5164
5165    cdi->sum = buf.readFloat();
5166    cdi->sum2 = buf.readFloat();
5167
5168    return WrapNewOrange(cdi, type);
5169  PyCATCH
5170}
5171
5172
5173Py_ssize_t ContDistribution_len(PyObject *self)
5174{ PyTRY
5175    TContDistribution *cont = getContDistribution(self);
5176    return cont ? cont->size() : -1;
5177  PyCATCH_1
5178}
5179
5180
5181PyObject *ContDistribution_keys(PyObject *self) PYARGS(0, "() -> [string] | [float]")
5182{ PyTRY
5183    TContDistribution *cont = getContDistribution(self);
5184    if (!cont)
5185      return PYNULL;
5186
5187    PyObject *nl=PyList_New(cont->size());
5188    Py_ssize_t i=0;
5189    PITERATE(TContDistribution, ci, cont)
5190      PyList_SetItem(nl, i++, PyFloat_FromDouble((double)(*ci).first));
5191    return nl;
5192  PyCATCH
5193}
5194
5195
5196PyObject *ContDistribution_items(PyObject *self) PYARGS(0, "() -> [(string, float)] | [(float, float)]")
5197{ PyTRY
5198    TContDistribution *cont = getContDistribution(self);
5199    if (!cont)
5200      return PYNULL;
5201
5202    PyObject *nl=PyList_New(cont->size());
5203    Py_ssize_t i=0;
5204    PITERATE(TContDistribution, ci, cont)
5205      PyList_SetItem(nl, i++, Py_BuildValue("ff", (*ci).first, (*ci).second));
5206    return nl;
5207  PyCATCH
5208}
5209
5210
5211PyObject *ContDistribution_values(PyObject *self) PYARGS(0, "() -> list")
5212{ PyTRY
5213    TContDistribution *cont = getContDistribution(self);
5214    if (!cont)
5215      return PYNULL;
5216
5217    PyObject *nl = PyList_New(cont->size());
5218    Py_ssize_t i = 0;
5219    const_PITERATE(TContDistribution, ci, cont)
5220      PyList_SetItem(nl, i++, PyFloat_FromDouble((*ci).second));
5221    return nl;
5222  PyCATCH
5223}
5224
5225
5226PyObject *ContDistribution_percentile(PyObject *self, PyObject *arg) PYARGS(METH_VARARGS, "(int) -> float")
5227{ PyTRY
5228    TContDistribution *cont = getContDistribution(self);
5229    if (!cont)
5230      return PYNULL;
5231
5232    float perc;
5233    if (!PyArg_ParseTuple(arg, "f:ContDistribution.percentile", &perc))
5234      return PYNULL;
5235
5236    return PyFloat_FromDouble(cont->percentile(perc));
5237  PyCATCH
5238}
5239
5240
5241PyObject *ContDistribution_add(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(value, weight) -> Value")
5242{ PyTRY
5243    CAST_TO(TContDistribution, dist)
5244
5245    PyObject *index;
5246    float weight = 1.0;
5247    if (!PyArg_ParseTuple(args, "O|f", &index, &weight))
5248      PYERROR(PyExc_TypeError, "DiscDistribution.add: invalid arguments", PYNULL);
5249
5250    float f;
5251    if (PyNumber_ToFloat(index, f)) {
5252      dist->addfloat(f, weight);
5253      RETURN_NONE;
5254    }
5255
5256    TValue val;
5257    if (!convertFromPython(index, val, dist->variable))
5258      PYERROR(PyExc_TypeError, "ContDistriubtion.add: invalid arguments", PYNULL);
5259
5260    dist->add(val, weight);
5261    RETURN_NONE;
5262  PyCATCH;
5263}
5264
5265
5266PyObject *ContDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5267{ PyTRY
5268    TContDistribution *cont = getContDistribution(self);
5269    if (!cont)
5270      return PYNULL;
5271
5272    return PyFloat_FromDouble(cont->error());
5273  PyCATCH
5274}
5275
5276
5277PyObject *ContDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5278{ PyTRY
5279    TContDistribution *cont = getContDistribution(self);
5280    if (!cont)
5281      return PYNULL;
5282
5283    return PyFloat_FromDouble(cont->average());
5284  PyCATCH
5285}
5286
5287
5288PyObject *ContDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5289{ PyTRY
5290    TContDistribution *cont = getContDistribution(self);
5291    if (!cont)
5292      return PYNULL;
5293
5294    return PyFloat_FromDouble(cont->dev());
5295  PyCATCH
5296}
5297
5298
5299PyObject *ContDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5300{ PyTRY
5301    TContDistribution *cont = getContDistribution(self);
5302    if (!cont)
5303      return PYNULL;
5304
5305    return PyFloat_FromDouble(cont->var());
5306  PyCATCH
5307}
5308
5309
5310PyObject *ContDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5311{ PyTRY
5312    TContDistribution *cont = getContDistribution(self);
5313    float x;
5314    if (!cont || !PyArg_ParseTuple(args, "f:ContDistribution.density", &x))
5315      return PYNULL;
5316
5317    return PyFloat_FromDouble(cont->p(x));
5318  PyCATCH
5319}
5320
5321
5322PyObject *GaussianDistribution_new(PyTypeObject *type, PyObject *args, PyObject *) BASED_ON(Distribution - Orange.statistics.distribution.Gaussian, "(mean, sigma) | (distribution) | () -> distribution") ALLOWS_EMPTY
5323{ PyTRY
5324    float mean = 0.0, sigma = 1.0;
5325
5326    if (PyArg_ParseTuple(args, "|ff", &mean, &sigma))
5327      return WrapNewOrange(mlnew TGaussianDistribution(mean, sigma), type);
5328
5329    PyErr_Clear();
5330
5331    PDistribution dist;
5332    if (PyArg_ParseTuple(args, "O&", &cc_Distribution, &dist))
5333      return WrapNewOrange(mlnew TGaussianDistribution(dist), type);
5334
5335    PYERROR(PyExc_TypeError, "GaussianDistribution expects mean and sigma, or distribution or nothing", PYNULL)
5336
5337  PyCATCH
5338}
5339
5340
5341PyObject *GaussianDistribution_average(PyObject *self) PYARGS(0, "() -> float")
5342{ PyTRY
5343    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).average());
5344  PyCATCH
5345}
5346
5347
5348PyObject *GaussianDistribution_error(PyObject *self) PYARGS(0, "() -> float")
5349{ PyTRY
5350    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).error());
5351  PyCATCH
5352}
5353
5354
5355PyObject *GaussianDistribution_dev(PyObject *self) PYARGS(0, "() -> float")
5356{ PyTRY
5357    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).dev());
5358  PyCATCH
5359}
5360
5361
5362PyObject *GaussianDistribution_var(PyObject *self) PYARGS(0, "() -> float")
5363{ PyTRY
5364    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).var());
5365  PyCATCH
5366}
5367
5368
5369PyObject *GaussianDistribution_density(PyObject *self, PyObject *args) PYARGS(METH_VARARGS, "(x) -> float")
5370{ PyTRY
5371    float x;
5372    if (!PyArg_ParseTuple(args, "f:GaussianDistribution.density", &x))
5373      return PYNULL;
5374
5375    return PyFloat_FromDouble(SELF_AS(TGaussianDistribution).p(x));
5376  PyCATCH
5377}
5378
5379
5380/* We redefine new (removed from below!) and add mapping methods
5381*/
5382
5383PyObject *getClassDistribution(PyObject *type, PyObject *args) PYARGS(METH_VARARGS, "(examples[, weightID]) -> Distribution")
5384{ PyTRY
5385    int weightID;
5386    PExampleGenerator gen = exampleGenFromArgs(args, weightID);
5387    if (!gen)
5388      return PYNULL;
5389    return WrapOrange(getClassDistribution(gen, weightID));
5390  PyCATCH
5391}
5392
5393
5394/* modified new (defined below), modified getitem, setitem */
5395
5396PDomainDistributions PDomainDistributions_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5397PyObject *DomainDistributions_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5398PyObject *DomainDistributions_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5399int       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); }
5400PyObject *DomainDistributions_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5401int       DomainDistributions_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5402Py_ssize_t       DomainDistributions_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_len(self); }
5403PyObject *DomainDistributions_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5404PyObject *DomainDistributions_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5405PyObject *DomainDistributions_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5406PyObject *DomainDistributions_str(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5407PyObject *DomainDistributions_repr(TPyOrange *self) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_str(self); }
5408int       DomainDistributions_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5409PyObject *DomainDistributions_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5410PyObject *DomainDistributions_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5411PyObject *DomainDistributions_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5412PyObject *DomainDistributions_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DomainDistributions") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5413PyObject *DomainDistributions_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5414PyObject *DomainDistributions_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5415PyObject *DomainDistributions_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_native(self); }
5416PyObject *DomainDistributions_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5417PyObject *DomainDistributions_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5418PyObject *DomainDistributions_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5419PyObject *DomainDistributions_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5420PyObject *DomainDistributions__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5421
5422
5423/* Note that this is not like callable-constructors. They return different type when given
5424   parameters, while this one returns the same type, disregarding whether it was given examples or not.
5425*/
5426PyObject *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
5427{ PyTRY
5428    if (!args || !PyTuple_Size(args))
5429      return WrapNewOrange(mlnew TDomainDistributions(), type);
5430
5431    int weightID = 0;
5432    PExampleGenerator gen;
5433    int skipDiscrete=0, skipContinuous=0;
5434    if (PyArg_ParseTuple(args, "O&|O&ii:Distribution.new", &pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID, &skipDiscrete, &skipContinuous))
5435      return WrapNewOrange(mlnew TDomainDistributions(gen, weightID, skipDiscrete!=0, skipContinuous!=0), type);
5436
5437    PyErr_Clear();
5438
5439    PyObject *obj = ListOfWrappedMethods<PDomainDistributions, TDomainDistributions, PDistribution, &PyOrDistribution_Type>::_new(type, args, keywds);
5440    if (obj)
5441      if (obj!=Py_None)
5442        return obj;
5443      else
5444        Py_DECREF(obj);
5445
5446    PyErr_Clear();
5447    PYERROR(PyExc_TypeError, "DomainDistributions.__init__ expect examples or a list of Distributions", PYNULL);
5448
5449  PyCATCH
5450}
5451
5452
5453/* We keep the sequence methods and add mapping interface */
5454
5455int DomainDistributions_getItemIndex(PyObject *self, PyObject *args)
5456{ CAST_TO_err(TDomainDistributions, bas, -1);
5457
5458  if (PyInt_Check(args)) {
5459    int i=(int)PyInt_AsLong(args);
5460    if ((i>=0) && (i<int(bas->size())))
5461      return i;
5462    else
5463      PYERROR(PyExc_IndexError, "index out of range", -1);
5464  }
5465
5466  if (PyString_Check(args)) {
5467    char *s=PyString_AsString(args);
5468    PITERATE(TDomainDistributions, ci, bas)
5469      if ((*ci)->variable && ((*ci)->variable->get_name()==s))
5470        return ci - bas->begin();
5471
5472    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", s);
5473    return -1;
5474  }
5475
5476  if (PyOrVariable_Check(args)) {
5477    PVariable var = PyOrange_AsVariable(args);
5478    PITERATE(TDomainDistributions, ci, bas)
5479      if ((*ci)->variable && ((*ci)->variable==var))
5480        return ci - bas->begin();
5481
5482    PyErr_Format(PyExc_IndexError, "attribute '%s' not found in domain", var->get_name().length() ? var->get_name().c_str() : "<no name>");
5483    return -1;
5484  }
5485
5486  PYERROR(PyExc_IndexError, "invalid index type", -1);
5487}
5488
5489
5490PyObject *DomainDistributions_getitem(PyObject *self, PyObject *args)
5491{ PyTRY
5492    int index=DomainDistributions_getItemIndex(self, args);
5493    if (index<0)
5494      return PYNULL;
5495    return WrapOrange(POrange(SELF_AS(TDomainDistributions).at(index)));
5496  PyCATCH
5497}
5498
5499
5500int DomainDistributions_setitem(PyObject *self, PyObject *args, PyObject *obj)
5501{ PyTRY
5502    PDistribution bas;
5503
5504    if (!PyOrBasicAttrStat_Check(obj))
5505      PYERROR(PyExc_TypeError, "invalid Distribution object", -1);
5506
5507    int index=DomainDistributions_getItemIndex(self, args);
5508    if (index==-1)
5509      return -1;
5510
5511    SELF_AS(TDomainDistributions)[index] = PyOrange_AsDistribution(obj);
5512    return 0;
5513  PyCATCH_1
5514}
5515
5516
5517PDistributionList PDistributionList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::P_FromArguments(arg); }
5518PyObject *DistributionList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_FromArguments(type, arg); }
5519PyObject *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); }
5520PyObject *DistributionList_getitem_sq(TPyOrange *self, Py_ssize_t index) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getitem(self, index); }
5521int       DistributionList_setitem_sq(TPyOrange *self, Py_ssize_t index, PyObject *item) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_setitem(self, index, item); }
5522PyObject *DistributionList_getslice(TPyOrange *self, Py_ssize_t start, Py_ssize_t stop) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_getslice(self, start, stop); }
5523int       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); }
5524Py_ssize_t       DistributionList_len_sq(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_len(self); }
5525PyObject *DistributionList_richcmp(TPyOrange *self, PyObject *object, int op) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_richcmp(self, object, op); }
5526PyObject *DistributionList_concat(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_concat(self, obj); }
5527PyObject *DistributionList_repeat(TPyOrange *self, Py_ssize_t times) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_repeat(self, times); }
5528PyObject *DistributionList_str(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5529PyObject *DistributionList_repr(TPyOrange *self) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_str(self); }
5530int       DistributionList_contains(TPyOrange *self, PyObject *obj) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_contains(self, obj); }
5531PyObject *DistributionList_append(TPyOrange *self, PyObject *item) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_append(self, item); }
5532PyObject *DistributionList_extend(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(sequence) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_extend(self, obj); }
5533PyObject *DistributionList_count(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_count(self, obj); }
5534PyObject *DistributionList_filter(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([filter-function]) -> DistributionList") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_filter(self, args); }
5535PyObject *DistributionList_index(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> int") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_index(self, obj); }
5536PyObject *DistributionList_insert(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(index, item) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_insert(self, args); }
5537PyObject *DistributionList_native(TPyOrange *self) PYARGS(METH_NOARGS, "() -> list") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_native(self); }
5538PyObject *DistributionList_pop(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "() -> Distribution") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_pop(self, args); }
5539PyObject *DistributionList_remove(TPyOrange *self, PyObject *obj) PYARGS(METH_O, "(Distribution) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_remove(self, obj); }
5540PyObject *DistributionList_reverse(TPyOrange *self) PYARGS(METH_NOARGS, "() -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reverse(self); }
5541PyObject *DistributionList_sort(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "([cmp-func]) -> None") { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_sort(self, args); }
5542PyObject *DistributionList__reduce__(TPyOrange *self, PyObject *) { return ListOfWrappedMethods<PDistributionList, TDistributionList, PDistribution, &PyOrDistribution_Type>::_reduce(self); }
5543
5544
5545
5546/* ************ LEARNER ************ */
5547
5548#include "classify.hpp"
5549#include "learn.hpp"
5550
5551BASED_ON(EFMDataDescription, Orange)
5552
5553PyObject *EFMDataDescription__reduce__(PyObject *self)
5554{
5555  CAST_TO(TEFMDataDescription, edd);
5556
5557  TCharBuffer buf(0);
5558  buf.writeFloatVector(edd->averages);
5559  buf.writeFloatVector(edd->matchProbabilities);
5560  buf.writeInt(edd->originalWeight);
5561  buf.writeInt(edd->missingWeight);
5562
5563  return Py_BuildValue("O(OOs#)N", getExportedFunction("__pickleLoaderEFMDataDescription"),
5564                                  WrapOrange(edd->domain),
5565                                  WrapOrange(edd->domainDistributions),
5566                                  buf.buf, buf.length(),
5567                                  packOrangeDictionary(self));
5568}
5569
5570
5571PyObject *__pickleLoaderEFMDataDescription(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(domain, domainDistributions, packed_data)")
5572{
5573  PDomain domain;
5574  PDomainDistributions domainDistributions;
5575  char *pbuf;
5576  int bufSize;
5577
5578  if (!PyArg_ParseTuple(args, "O&O&s#", ccn_Domain, &domain, ccn_DomainDistributions, &domainDistributions, &pbuf, &bufSize))
5579    return PYNULL;
5580
5581  TEFMDataDescription *edd = new TEFMDataDescription(domain, domainDistributions);
5582  PEFMDataDescription wedd = edd;
5583
5584  TCharBuffer buf(pbuf);
5585  buf.readFloatVector(edd->averages);
5586  buf.readFloatVector(edd->matchProbabilities);
5587  edd->originalWeight = buf.readInt();
5588  edd->missingWeight = buf.readInt();
5589
5590  return WrapOrange(wedd);
5591}
5592
5593
5594ABSTRACT(LearnerFD - Orange.classification.LearnerFD, Learner)
5595
5596PyObject *Learner_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(Orange - Orange.classification.Learner, "<abstract>")
5597{ if (type == (PyTypeObject *)&PyOrLearner_Type)
5598    return setCallbackFunction(WrapNewOrange(mlnew TLearner_Python(), type), args);
5599  else
5600    return WrapNewOrange(mlnew TLearner_Python(), type);
5601}
5602
5603
5604PyObject *Learner__reduce__(PyObject *self)
5605{
5606  return callbackReduce(self, PyOrLearner_Type);
5607}
5608
5609
5610PyObject *Learner_call(PyObject *self, PyObject *targs, PyObject *keywords) PYDOC("(examples) -> Classifier")
5611{
5612  PyTRY
5613    NO_KEYWORDS
5614
5615    if (PyOrange_OrangeBaseClass(self->ob_type) == &PyOrLearner_Type) {
5616      PyErr_Format(PyExc_SystemError, "Learner.call called for '%s': this may lead to stack overflow", self->ob_type->tp_name);
5617      return PYNULL;
5618    }
5619
5620    PExampleGenerator egen;
5621    int weight = 0;
5622    if (!PyArg_ParseTuple(targs, "O&|O&", pt_ExampleGenerator, &egen, pt_weightByGen(egen), &weight))
5623      PYERROR(PyExc_AttributeError, "Learner.__call__: examples and, optionally, weight attribute expected", PYNULL);
5624
5625    // Here for compatibility with obsolete scripts
5626/*    if (PyTuple_Size(targs)==1) {
5627      if (((TPyOrange *)self)->orange_dict) {
5628        PyObject *pyweight = PyDict_GetItemString(((TPyOrange *)self)->orange_dict, "weight");
5629        if (pyweight && PyInt_Check(pyweight))
5630          weight = (int)PyInt_AsLong(pyweight);
5631      }
5632    }
5633*/
5634    PClassifier classfr = SELF_AS(TLearner)(egen, weight);
5635    if (!classfr)
5636      PYERROR(PyExc_SystemError, "learning failed", PYNULL);
5637
5638    return WrapOrange(classfr);
5639  PyCATCH
5640}
5641
5642
5643
5644
5645/* ************ CLASSIFIERS ************ */
5646
5647#include "classify.hpp"
5648#include "majority.hpp"
5649
5650ABSTRACT(ClassifierFD - Orange.classification.ClassifierFD, Classifier)
5651
5652PyObject *DefaultClassifier_new(PyTypeObject *tpe, PyObject *args, PyObject *kw) BASED_ON(Classifier - Orange.classification.ConstantClassifier, "([defaultVal])") ALLOWS_EMPTY
5653{
5654  PyObject *arg1 = NULL, *arg2 = NULL;
5655  if (!PyArg_UnpackTuple(args, "DefaultClassifier.__new__", 0, 2, &arg1, &arg2))
5656    return PYNULL;
5657
5658  if (!arg1)
5659    return WrapNewOrange(mlnew TDefaultClassifier(), tpe);
5660
5661  if (!arg2) {
5662    if (PyOrVariable_Check(arg1))
5663      return WrapNewOrange(mlnew TDefaultClassifier(PyOrange_AsVariable(arg1)), tpe);
5664    TValue val;
5665    if (convertFromPython(arg1, val)) {
5666      PVariable var = PyOrValue_Check(arg1) ? PyValue_AS_Variable(arg1) : PVariable();
5667      return WrapNewOrange(mlnew TDefaultClassifier(var, val, PDistribution()), tpe);
5668    }
5669  }
5670
5671  else
5672    if (PyOrVariable_Check(arg1)) {
5673      PVariable classVar = PyOrange_AsVariable(arg1);
5674      TValue val;
5675      if (convertFromPython(arg2, val, classVar))
5676        return WrapNewOrange(mlnew TDefaultClassifier(classVar, val, PDistribution()), tpe);
5677    }
5678
5679  PYERROR(PyExc_TypeError, "DefaultClassifier's constructor expects a Variable, a Value or both", PYNULL);
5680}
5681
5682C_NAMED(RandomLearner - Orange.classification.RandomLearner, Learner, "([probabilities=])")
5683C_NAMED(RandomClassifier - Orange.classification.RandomClassifier, Classifier, "([probabilities=])")
5684
5685PClassifierList PClassifierList_FromArguments(PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::P_FromArguments(arg); }
5686PyObject *ClassifierList_FromArguments(PyTypeObject *type, PyObject *arg) { return ListOfWrappedMethods<PClassifierList, TClassifierList, PClassifier, &PyOrClassifier_Type>::_FromArguments(type, arg); }
5687PyObject *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, k