source: orange/source/orange/lib_kernel.cpp @ 9529:fe01d5187ea0

Revision 9529:fe01d5187ea0, 205.0 KB checked in by ales_erjavec <ales.erjavec@…>, 2 years ago (diff)

Fixed pickleLoaderDomain so it can load domains stored prior to the multiclass support.

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