source: orange/source/orange/lib_kernel.cpp @ 11001:f21cde875fe9

Revision 11001:f21cde875fe9, 213.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 18 months ago (diff)

Clear invalid PyObject pointers stored in a global variable which outlives the python interpreter.

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