source: orange/source/orange/cls_example.cpp @ 11703:9b8d8ab7820c

Revision 11703:9b8d8ab7820c, 34.6 KB checked in by janezd <janez.demsar@…>, 7 months ago (diff)

Removed the GPL copyright notice from all files except orangeqt.

Line 
1#include "orange.hpp"
2
3class TMLClassDefinition;
4extern TMLClassDefinition MLDef_Domain;
5extern TMLClassDefinition MLDef_Variable;
6
7#include "vars.hpp"
8#include "domain.hpp"
9#include "examples.hpp"
10
11#include "cls_value.hpp"
12#include "cls_example.hpp"
13#include "cls_orange.hpp"
14#include "lib_kernel.hpp"
15#include "converts.hpp"
16
17#include "externs.px"
18
19
20DATASTRUCTURE(Example - Orange.data.Instance, TPyExample, 0)
21
22
23bool convertFromPythonExisting(PyObject *lst, TExample &example)
24{
25  PDomain dom=example.domain;
26
27  if (PyOrExample_Check(lst)) {
28    const TExample &orex = PyExample_AS_ExampleReference(lst);
29    if (orex.domain != dom)
30      dom->convert(example, orex);
31    else
32      example = orex;
33    return true;
34  }
35
36  if (!PyList_Check(lst)) {
37    PyErr_Format(PyExc_TypeError, "invalid argument type (expected list, got '%s)", lst ? lst->ob_type->tp_name : "None");
38    return false;
39  }
40
41  int const nvars = dom->variables->size() + dom->classVars->size();
42  if (Py_ssize_t(nvars) != PyList_Size(lst)) {
43    PyErr_Format(PyExc_IndexError, "invalid list size (got %i, expected %i items)",
44        PyList_Size(lst), nvars);
45    return false;
46  }
47
48  Py_ssize_t pos = 0;
49  TExample::iterator ei(example.begin());
50  TVarList::iterator vi(dom->variables->begin());
51  TVarList::const_iterator const ve(dom->variables->end());
52  TVarList::const_iterator const ce(dom->classVars->end());
53  while(vi != ce && vi != ve) {
54    PyObject *li=PyList_GetItem(lst, pos++);
55    if (!li)
56      PYERROR(PyExc_SystemError, "can't read the list", false);
57
58    if (PyOrValue_Check(li))
59      if (PyValue_AS_Variable(li) ? (PyValue_AS_Variable(li) != *vi) : (PyValue_AS_Value(li).varType=!(*vi)->varType) ) {
60        PyErr_Format(PyExc_TypeError, "wrong value type for attribute no. %i (%s)", pos, (*vi)->get_name().c_str());
61        return false;
62      }
63      else
64        *(ei++)=PyValue_AS_Value(li);
65
66    else {
67      if (li == Py_None) {
68        *(ei++) = (*vi)->DK();
69      } else if (PyString_Check(li)) {
70          (*vi)->str2val(string(PyString_AsString(li)), *(ei++));
71      } else if ((*vi)->varType==TValue::INTVAR) {
72        if (PyInt_Check(li)) {
73          TEnumVariable * enumvar = dynamic_cast<TEnumVariable *>(vi->getUnwrappedPtr());
74          int value = int(PyInt_AsLong(li));
75          if (value < 0 || value >= enumvar->noOfValues()) {
76            PyErr_Format(PyExc_ValueError,
77                         "value index %i out of range (0 - %i) at attribute no %i (%s)",
78                         value, enumvar->noOfValues() - 1, pos, enumvar->get_name().c_str());
79            return false;
80          }
81          *(ei++) = TValue(value);
82        } else {
83          PyErr_Format(PyExc_TypeError, "attribute no. %i (%s) is ordinal, string or int value expected", pos, (*vi)->get_name().c_str());
84          return false;
85        }
86      }
87      else if ((*vi)->varType==TValue::FLOATVAR) {
88        float f;
89        if (PyNumber_ToFloat(li, f))
90          *(ei++) = TValue(f);
91        else {
92          PyErr_Format(PyExc_TypeError, "attribute no. %i (%s) is continuous, float value expected", pos, (*vi)->get_name().c_str());
93          return false;
94        }
95      }
96      else
97        ei++;
98    }
99    if (++vi == ve) {
100        vi = dom->classVars->begin();
101    }
102  }
103
104  return true;
105}
106
107
108bool convertFromPython(PyObject *lst, TExample &example, PDomain dom)
109{ example=TExample(dom);
110  return convertFromPythonExisting(lst, example);
111}
112
113
114int cc_Example(PyObject *obj, void *ptr)
115{ if (!PyOrExample_Check(obj))
116    return 0;
117  *(PExample *)(ptr) = PyExample_AS_Example(obj);
118  return 1;
119}
120
121int ccn_Example(PyObject *obj, void *ptr)
122{ if (obj == Py_None) {
123    *(PExample *)(ptr) = PExample();
124    return 1;
125  }
126  else
127    return cc_Example(obj, ptr);
128}
129
130
131int ptr_Example(PyObject *obj, void *ptr)
132{ if (!PyOrExample_Check(obj))
133    return 0;
134  *(TExample **)(ptr) = PyExample_AS_Example(obj).getUnwrappedPtr();
135  return 1;
136}
137
138int ptrn_Example(PyObject *obj, void *ptr)
139{ if (obj == Py_None) {
140    *(TExample **)(ptr) = NULL;
141    return 1;
142  }
143  else
144    return ptr_Example(obj, ptr);
145}
146
147
148PyObject *Example_FromExample(PyTypeObject *type, PExample example, POrange lock)
149{ TPyExample *self=PyObject_GC_New(TPyExample, type);
150  self->example.init();
151  self->lock.init();
152  self->example = example;
153  self->lock = lock;
154  PyObject_GC_Track(self);
155  return (PyObject *)self;
156}
157
158
159void Example_dealloc(TPyExample *self)
160{ self->lock.~POrange();
161  self->example.~PExample();
162  /* Should not call tp_free if it is a reference
163     Destructor is also called by exit proc, not by wrapped */
164  if (PyObject_IsPointer(self)) {
165    PyObject_GC_UnTrack((PyObject *)self);
166    self->ob_type->tp_free((PyObject *)self); 
167  }
168}
169
170
171int Example_traverse(TPyExample *self, visitproc visit, void *arg)
172{ PVISIT(self->lock)
173  if (!self->lock) // don't visit if it's a reference!
174    PVISIT(self->example);
175
176  return 0;
177}
178
179int Example_clear(TPyExample *self)
180{ self->lock=POrange();
181  self->example=PExample();
182  return 0;
183}
184
185
186bool readBoolFlag(PyObject *keywords, char *flag);
187
188CONSTRUCTOR_KEYWORDS(Example, "filterMetas filter_metas")
189
190
191PyObject *Example_new(PyTypeObject *type, PyObject *args, PyObject *keywords) BASED_ON(ROOT, "(domain, [list of values])")
192{ PyTRY
193    PyObject *list=PYNULL;
194    PDomain dom;
195
196    if (PyArg_ParseTuple(args, "O&|O", cc_Domain, &dom, &list)) {
197      if (list && PyOrExample_Check(list)) {
198        PExample ex = mlnew TExample(dom, PyExample_AS_Example(list).getReference(), readBoolFlag(keywords, "filterMetas") || readBoolFlag(keywords, "filter_metas"));
199        return Example_FromWrappedExample(ex);
200      }
201
202      PyObject *example = Example_FromDomain(dom);
203     
204      if (list) {
205        if (PyList_Check(list) && PyList_Size(list) && PyOrExample_Check(PyList_GET_ITEM(list, 0))) {
206          TExampleList elist;
207          PyObject *iterator = PyObject_GetIter(list);
208          PyObject *item = PyIter_Next(iterator);
209          for(; item; item = PyIter_Next(iterator)) {
210            if (!PyOrExample_Check(item)) {
211              Py_DECREF(item);
212              break;
213            }
214            elist.push_back(PyExample_AS_Example(item));
215            Py_DECREF(item);
216          }
217          Py_DECREF(iterator);
218          if (item)
219            raiseError("invalid elements in list for example join");
220          else {
221            PExample ex = mlnew TExample(dom, PExampleList(elist));
222            return Example_FromWrappedExample(ex);
223          }
224        }
225        else if (!convertFromPythonExisting(list, PyExample_AS_ExampleReference(example))) {
226          Py_DECREF(example);
227          return PYNULL;
228        }
229      }
230
231      return example;
232    }
233
234    PyErr_Clear();
235
236    PExample example;
237    int keepId = 0;
238    if (PyArg_ParseTuple(args, "O&|i", cc_Example, &example, &keepId)) {
239      PExample ex = mlnew TExample(example.getReference());
240      if (!keepId)
241        ex->id = getExampleId();
242      return Example_FromWrappedExample(ex);
243    }
244     
245    PYERROR(PyExc_TypeError, "domain and (optionally) list arguments accepted", PYNULL);
246  PyCATCH
247}
248
249
250
251int getMetaIdFromPy(PExample example, PyObject *index, PVariable &var)
252{ if (PyInt_Check(index)) {
253    int idx=PyInt_AsLong(index);
254    var=example->domain->getMetaVar(idx, false); // it may also be NULL
255    return idx;
256  }
257  else if (PyString_Check(index)) {
258    TMetaDescriptor const *desc=example->domain->metas[string(PyString_AsString(index))];
259    if (!desc) {
260      PyErr_Format(PyExc_IndexError, "invalid meta variable name '%s'", PyString_AsString(index));
261      return 0;
262    }
263    var=desc->variable;
264    return desc->id;
265  }
266  else if (PyOrVariable_Check(index)) {
267    var = PyOrange_AsVariable(index);
268    int idx = example->domain->getMetaNum(var, false);
269    if (idx == ILLEGAL_INT)
270      PYERROR(PyExc_IndexError, "invalid meta variable", 0);
271    return idx;
272  }
273
274  PYERROR(PyExc_IndexError, "invalid meta variable", 0);
275}
276
277
278int weightIndex(const TExample &example, PyObject *pyindex)
279{
280  if (pyindex == Py_None)
281    return 0;
282
283  if (PyInt_Check(pyindex))
284    return (int)PyInt_AsLong(pyindex);
285
286  PVariable var = varFromArg_byDomain(pyindex, example.domain);
287  if (!var) 
288    PYERROR(PyExc_TypeError, "invalid arguments or unknown attribute", ILLEGAL_INT);
289
290  return example.domain->getVarNum(var);
291}
292
293
294PyObject *Example_reference(TPyExample *pex) PYARGS(METH_NOARGS, "unique reference (pointer to) the object")
295{
296  return PyInt_FromSize_t(size_t(&PyExample_AS_ExampleReference(pex)));
297}
298
299
300PyObject *Example_get_weight(TPyExample *pex, PyObject *pyindex) PYARGS(METH_O, "(id) -> weight; Returns example's weight")
301{
302  PyTRY
303    const TExample &example = PyExample_AS_ExampleReference(pex);
304    int index = weightIndex(example, pyindex);
305    if (index == ILLEGAL_INT)
306      return PYNULL;
307
308    if (!index)
309      return PyFloat_FromDouble(1.0);
310
311    TValue val = example.getMeta(index);
312    if (val.isSpecial() || (val.varType!=TValue::FLOATVAR))
313      PYERROR(PyExc_TypeError, "invalid weight", PYNULL);
314
315    return PyFloat_FromDouble((double)val.floatV);
316  PyCATCH
317}
318
319
320PyObject *Example_set_weight(TPyExample *pex, PyObject *args) PYARGS(METH_VARARGS, "(id[, weight]); Sets example's weight to given value")
321{ PyTRY
322    PyObject *pyindex;
323    float weight = 1;
324
325    if (!PyArg_ParseTuple(args, "O|f:setweight", &pyindex, &weight))
326      return PYNULL;
327
328    TExample &example = PyExample_AS_ExampleReference(pex);
329    int index = weightIndex(example, pyindex);
330
331    if (index == ILLEGAL_INT)
332      return PYNULL;
333
334    if (index>0)
335      PYERROR(PyExc_IndexError, "Example.setweight: invalid weight id", PYNULL);     
336
337    if (index)
338      example.setMeta(index, TValue(weight));
339
340    RETURN_NONE;
341  PyCATCH
342}
343
344
345PyObject *Example_remove_weight(TPyExample *pex, PyObject *pyindex) PYARGS(METH_O, "(id); Removes examples's weight")
346{ PyTRY
347    TExample &example = PyExample_AS_ExampleReference(pex);
348    int index = weightIndex(example, pyindex);
349
350    if (index == ILLEGAL_INT)
351      return PYNULL;
352
353    if (index>0)
354      PYERROR(PyExc_IndexError, "Example.setweight: invalid weight id", PYNULL);     
355
356    if (index)
357      example.removeMeta(index);
358
359    RETURN_NONE;
360  PyCATCH
361}
362
363
364PyObject *Example_get_meta(TPyExample *pex, PyObject *index) PYARGS(METH_O, "(id | var) -> Value; Gets a meta-value")
365{ PyTRY
366    PVariable var;
367    int idx = getMetaIdFromPy(PyExample_AS_Example(pex), index, var);
368    if (!idx)
369      return PYNULL; 
370
371    return convertToPythonNative(PyExample_AS_Example(pex)->getMeta(idx), var);
372
373    // This could be better, but I wouldn't dare to change this
374    // return Value_FromVariableValue(var, PyExample_AS_Example(pex)->getMeta(idx));
375  PyCATCH
376}
377
378
379PyObject *Example_get_metas(TPyExample *pex, PyObject *args) PYARGS(METH_VARARGS, "([key-type]) -> dictionary with a copy of example's meta attributes")
380{
381  PyTRY
382    PyObject *pyoptional = NULL;
383    PyTypeObject *keytype = NULL;
384    int optional = ILLEGAL_INT;
385    if (!PyArg_ParseTuple(args, "|OO:Example.getmetas", &pyoptional, &keytype))
386      return NULL;
387
388    if (!keytype) {
389      if (pyoptional && PyType_Check(pyoptional)) {
390        keytype = (PyTypeObject *)pyoptional;
391        pyoptional = NULL;
392      }
393      else {
394        keytype = &PyInt_Type;
395      }
396    }
397   
398    if (pyoptional) {
399      if (!PyInt_Check(pyoptional)) {
400        PyErr_Format(PyExc_TypeError, "invalid type for argument 'optional' (expected int, got '%s')", pyoptional->ob_type->tp_name);
401        return NULL;
402      }
403      optional = PyInt_AsLong(pyoptional);
404    }
405   
406    if ((keytype != &PyInt_Type) && (keytype != &PyString_Type) && (keytype != (PyTypeObject *)&PyOrVariable_Type))
407      PYERROR(PyExc_TypeError, "invalid key type (should be nothing, int, str, or orange.Variable)", NULL);
408     
409    PExample ex = PyExample_AS_Example(pex);
410    const TDomain &dom = ex->domain.getReference();
411
412    PyObject *res = PyDict_New();
413
414    try {
415      const_ITERATE(TMetaValues, mi, ex->meta) {
416        const TMetaDescriptor *md = dom.getMetaDescriptor(mi->first, false);
417       
418        if ((optional != ILLEGAL_INT) && (!md || (md->optional != optional)))
419          continue;
420       
421        PyObject *key;
422        PVariable variable = md ? md->variable : PVariable();
423       
424        if (keytype == &PyInt_Type)
425          key = PyInt_FromLong(mi->first);
426        else {
427          if (!variable)
428            continue;
429          if (keytype == &PyString_Type)
430            key = PyString_FromString(variable->get_name().c_str());
431          else
432            key = WrapOrange(variable);
433        }
434
435        PyObject *value = Value_FromVariableValue(variable, mi->second);
436        PyDict_SetItem(res, key, value);
437        Py_DECREF(key);
438        Py_DECREF(value);
439      }
440
441      return res;
442    }
443    catch (...) {
444      Py_DECREF(res);
445      throw;
446    }
447
448  PyCATCH
449
450}
451
452
453PyObject *Example_has_meta(TPyExample *pex, PyObject *index) PYARGS(METH_O, "(id | var) -> bool")
454{ PyTRY
455    PVariable var;
456    int idx = getMetaIdFromPy(PyExample_AS_Example(pex), index, var);
457    PyErr_Clear();
458    return PyInt_FromLong(idx && PyExample_AS_Example(pex)->hasMeta(idx) ? 1 : 0);
459  PyCATCH
460}
461
462
463PyObject *Example_set_value(TPyExample *pex, PyObject *vala) PYARGS(METH_O, "(Value) -> None")
464{ PyTRY
465    if (!PyOrValue_Check(vala))
466      PYERROR(PyExc_TypeError, "Example.setvalue: orange.Value expected", PYNULL);
467
468    PVariable var = PyValue_AS_Variable(vala);
469    if (!var)
470      PYERROR(PyExc_TypeError, "Example.setvalue: values 'variable' should not be None", PYNULL);
471
472    PExample example=PyExample_AS_Example(pex);
473    int idx = example->domain->getVarNum(var);
474
475    if (idx>=0)
476      example->operator[](idx) = PyValue_AS_Value(vala);
477    else
478      example->setMeta(idx, PyValue_AS_Value(vala));
479
480    RETURN_NONE;
481  PyCATCH
482}
483
484
485PyObject *Example_set_meta(TPyExample *pex, PyObject *args) PYARGS(METH_VARARGS, "(Value, int) | (variable, value); Sets a meta-value")
486{ PyTRY
487    PExample example=PyExample_AS_Example(pex);
488 
489    PyObject *par1, *par2=PYNULL;
490    if (!PyArg_ParseTuple(args, "O|O", &par1, &par2))
491      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL);
492
493    int idx=0;
494
495    if (PyOrValue_Check(par1)) {
496      // first parameter is a PyValue
497      // second parameter is an index and is accepted iff variable not among domain's meta variables
498      TMetaDescriptor *desc=PyValue_AS_Variable(par1) ? example->domain->metas[PyValue_AS_Variable(par1)] : (TMetaDescriptor *)NULL;
499      if (desc) 
500        if (par2)
501          PYERROR(PyExc_TypeError, "second argument (index) not expected", PYNULL)
502        else
503          idx=desc->id;
504      else
505       if (!par2)
506         PYERROR(PyExc_TypeError, "second argument (index) needed", PYNULL)
507       else
508         if (!PyInt_Check(par2))
509           PYERROR(PyExc_TypeError, "invalid index type (int expected)", PYNULL)
510         else {
511           idx = int(PyInt_AsLong(par2));
512           if (idx>=0)
513             PYERROR(PyExc_TypeError, "invalid meta-id index (negative integer expected)", PYNULL);
514         }
515
516      example->setMeta(idx, PyValue_AS_Value(par1));
517    }
518
519    else if (!par2)
520      PYERROR(PyExc_TypeError, "invalid arguments (second argument missing or the first is of wrong type)", PYNULL)
521
522    else if (PyOrVariable_Check(par1) || PyString_Check(par1) || PyInt_Check(par1)) {
523      // first parameter will denote the variable, the second the value
524      int idx;
525      PVariable var;
526
527      if (PyInt_Check(par1)) {
528        idx = PyInt_AsLong(par1);
529        TMetaDescriptor *desc=example->domain->metas[idx];
530        if (desc)
531          var = desc->variable;
532      }
533
534      else {
535        TMetaDescriptor *desc=example->domain->metas[
536            PyOrVariable_Check(par1) ? PyOrange_AsVariable(par1)->get_name()
537                                     : string(PyString_AsString(par1))];
538        if (!desc)
539          PYERROR(PyExc_TypeError, "invalid variable", PYNULL);
540        idx = desc->id;
541        var = desc->variable;
542      }
543
544      if (idx>=0)
545        PYERROR(PyExc_TypeError, "invalid meta-id index (negative integer expected)", PYNULL);
546
547      TValue val;
548      if (!convertFromPython(par2, val, var))
549        return PYNULL;
550      example->setMeta(idx, val);
551    }
552
553    else
554      PYERROR(PyExc_TypeError, "invalid arguments", PYNULL)
555
556    RETURN_NONE;
557  PyCATCH
558}
559 
560
561PyObject *Example_remove_meta(TPyExample *pex, PyObject *index) PYARGS(METH_O, "(id); Removes a meta-value")
562{ PyTRY
563    PVariable var;
564    int idx = getMetaIdFromPy(PyExample_AS_Example(pex), index, var);
565    if (!idx)
566      return PYNULL; 
567
568    PyExample_AS_Example(pex)->removeMeta(idx);
569    RETURN_NONE;
570  PyCATCH
571}
572
573
574
575PyObject *Example_get_class(TPyExample *pex) PYARGS(METH_NOARGS, "()  -> Value; Returns example's class")
576{ PyTRY
577      const TExample &example = PyExample_AS_ExampleReference(pex);
578      const PVariable &classVar = example.domain->classVar;
579
580      if (!classVar)
581        raiseError("class-less domain");
582
583      return Value_FromVariableValue(classVar, example.getClass());
584  PyCATCH
585}
586
587
588PyObject *Example_get_classes(TPyExample *pex) PYARGS(METH_NOARGS, "()  -> [Values]; Returns example's class")
589{ PyTRY
590      const TExample &example = PyExample_AS_ExampleReference(pex);
591      PyObject *list=PyList_New(0);
592      TExample::const_iterator ei=example.values_end;
593      const_PITERATE(TVarList, vi, example.domain->classVars) {
594          PyObject *valo = Value_FromVariableValue(*vi, *ei++);
595          PyList_Append(list, valo);
596          Py_DECREF(valo);
597      }
598      return list;
599  PyCATCH
600}
601
602
603PyObject *Example_set_class(TPyExample *pex, PyObject *val) PYARGS(METH_O, "(value); Sets example's class")
604{ PyTRY
605    PExample &example=PyExample_AS_Example(pex);
606    PVariable &classVar = example->domain->classVar;
607
608    if (!classVar)
609      PYERROR(PyExc_SystemError, "classless domain", PYNULL);
610
611    TValue value;
612    if (!convertFromPython(val, value, classVar)) 
613      return PYNULL;
614    example->setClass(value);
615
616    RETURN_NONE;
617  PyCATCH
618}
619
620
621PyObject *Example_set_classes(TPyExample *pex, PyObject *val) PYARGS(METH_O, "(list-of-Values); Returns example's class")
622{ PyTRY
623      const TExample &example = PyExample_AS_ExampleReference(pex);
624      if (!PyList_Check(val)) {
625          PYERROR(PyExc_TypeError, "list of values expected", PYNULL);
626      }
627      if (PyList_Size(val) != example.domain->classVars->size()) {
628          PyErr_Format(PyExc_IndexError, "expected %i values, got %i", example.domain->classVars->size(), PyList_Size(val));
629          return NULL;
630      }
631      TExample::iterator ei=example.values_end;
632      int pos = 0;
633      const_PITERATE(TVarList, vi, example.domain->classVars) {
634          if (!convertFromPython(PyList_GET_ITEM(val, pos++), *ei++, *vi))
635              return PYNULL;
636      }
637      RETURN_NONE;
638  PyCATCH
639}
640
641
642
643PyObject *Example_compatible(TPyExample *pex, PyObject *args) PYARGS(METH_VARARGS, "(example[, ignoreClass]); Returns true if examples are compatible")
644{ PyTRY
645    PExample example;
646    int ic = 0;
647    if (!PyArg_ParseTuple(args, "O&|i", cc_Example, &example, &ic))
648      PYERROR(PyExc_TypeError, "example and, optionally, a flag for ignoring the class expected", PYNULL)
649
650    return PyInt_FromLong(PyExample_AS_Example(pex)->compatible(example.getReference(), ic != 0) ? 1 : 0);
651  PyCATCH
652}
653
654
655PyObject *PyExampleIter_New(TPyExample *);
656
657PyObject *Example_iter(TPyExample *pex)
658{ return PyExampleIter_New(pex);
659}
660
661
662int getAttributeIndex(PDomain domain, PyObject *vara)
663{
664    if (PyInt_Check(vara)) {
665      int ind = int(PyInt_AsLong(vara));
666      if (ind >= (int)(domain->variables->size())) {
667        PyErr_Format(PyExc_IndexError, "index %i to large (> %i)", ind, domain->variables->size()-1);
668        return ILLEGAL_INT;
669      }
670
671      // Exception: example[-1] gives class value
672      return ind==-1 ? domain->variables->size()-1 : ind;
673    }
674
675    PVariable var=varFromArg_byDomain(vara, domain);
676    if (!var) 
677      PYERROR(PyExc_TypeError, "invalid arguments or unknown attribute name", ILLEGAL_INT);
678
679    return domain->getVarNum(var);
680}
681
682
683PyObject *Example_getitem(TPyExample *pex, PyObject *vara)
684{ PyTRY
685    PExample example = PyExample_AS_Example(pex);
686
687    int ind = getAttributeIndex(example->domain, vara);
688    if (ind==ILLEGAL_INT)
689      return PYNULL;
690
691    if ((ind < 0) && !example->hasMeta(ind)) {
692      TMetaDescriptor *metadesc = example->domain->metas[ind];
693      if (metadesc && metadesc->optional)
694        return Value_FromVariableValue(metadesc->variable, metadesc->variable->DK());
695    }
696   
697    /* getVar will return NULL if ind is meta-attribute not registered with the domain.
698       That's OK - we don't need PVariable (Value_FromValue would do exactly the same).
699       operator[] will raise an exception if meta-value is requested and the example
700       doesn't have it. */
701    return Value_FromVariableValue(example->domain->getVar(ind, false), example->operator[](ind));
702  PyCATCH
703}
704
705
706int Example_setitem(TPyExample *pex, PyObject *vara, PyObject *vala)
707{ PyTRY
708    PExample example = PyExample_AS_Example(pex);
709    const int ind = getAttributeIndex(example->domain, vara);
710    if (ind==ILLEGAL_INT)
711      return -1;
712
713    PVariable var = example->domain->getVar(ind, false);
714
715    if (PyOrValue_Check(vala)) {
716      if (PyValue_AS_Variable(vala) && var && (PyValue_AS_Variable(vala)!=var)) {
717          string vals;
718          PyValue_AS_Variable(vala)->val2str(PyValue_AS_Value(vala), vals);
719          if (ind>=0)
720            var->str2val(vals, example->operator[](ind));
721          else {
722            TValue val;
723            var->str2val(vals, val);
724            example->setMeta(ind, val);
725          }
726        }
727      else {
728        if (ind>=0)
729          example->operator[](ind) = PyValue_AS_Value(vala);
730        else
731          example->setMeta(ind, PyValue_AS_Value(vala));
732      }
733    }
734
735    else {
736      TValue value;
737      if (!convertFromPython(vala, value, var)) 
738        return -1;
739      if (ind>=0)
740        example->operator[](ind) = value;
741      else
742        example->setMeta(ind, value);
743    }
744
745    return 0;
746
747  PyCATCH_1
748}
749
750
751
752inline PyObject *toValue(const TValue &val, PVariable var, int natvt, PyObject *forDK, PyObject *forDC, PyObject *forSpecial)
753{ switch (natvt) {
754    case -1:
755      return (val.varType==TValue::INTVAR)
756            ? PyInt_FromLong(long(val.intV))
757            : PyFloat_FromDouble(double(val.floatV));
758
759    case  0:
760      if (val.isSpecial()) {
761        PyObject *res;
762        if (val.isDC())
763          res = forDC;
764        else if (val.isDK())
765          res = forDK;
766        else
767          res = forSpecial;
768        Py_INCREF(res);
769        return res;
770      }   
771      else
772        return convertToPythonNative(val, var);
773
774    default:
775      return Value_FromVariableValue(var, val);
776  }
777}
778
779PyObject *convertToPythonNative(const TExample &example, int natvt, bool tuples, PyObject *forDK, PyObject *forDC, PyObject *forSpecial)
780{
781  if (forDK)
782    Py_INCREF(forDK);
783  else
784    forDK = PyString_FromString("?");
785
786  if (forDC)
787    Py_INCREF(forDC);
788  else
789    forDC = PyString_FromString("~");
790
791  if (forSpecial)
792    Py_INCREF(forSpecial);
793  else
794    forSpecial = PyString_FromString(".");
795
796  PyObject *list=PyList_New(0);
797  TExample::const_iterator ei=example.begin();
798  const_PITERATE(TVarList, vi, example.domain->attributes) {
799    PyObject *valo = toValue(*(ei++), *vi, natvt, forDK, forDC, forSpecial);
800    PyList_Append(list, valo);
801    Py_DECREF(valo);
802  }
803
804  PyObject *res;
805
806  if (example.domain->classVar) {
807    PyObject *pyclass = toValue(example.getClass(), example.domain->classVar, natvt, forDK, forDC, forSpecial);
808    if (tuples)
809      res = Py_BuildValue("NN", list, pyclass);
810    else {
811      PyList_Append(list, pyclass);
812      Py_DECREF(pyclass);
813      res = list;
814    }
815  }
816   
817  else {
818    if (tuples)
819      res = Py_BuildValue("NO", list, Py_None);
820    else
821      res = list;
822  }
823
824  Py_DECREF(forDK);
825  Py_DECREF(forDC);
826  Py_DECREF(forSpecial);
827
828  return res;
829}
830
831
832PyObject *Example_native(TPyExample *pex, PyObject *args, PyObject *keyws) PYARGS(METH_VARARGS | METH_KEYWORDS, "([nativity, tuple=, substitute_DC=, substitute_DK=, substitute_Other=])  -> list; Converts an example to a list")
833{ PyTRY
834    int natvt=1;
835    if (args && !PyArg_ParseTuple(args, "|i", &natvt))
836      PYERROR(PyExc_TypeError, "invalid arguments (no arguments or an integer expected)", PYNULL);
837
838    bool tuples = false;
839    PyObject *pytuples = keyws ? PyDict_GetItemString(keyws, "tuple") : PYNULL;
840    tuples = pytuples && (PyObject_IsTrue(pytuples) != 0);
841
842    PyObject *forDC = NULL, *forDK = NULL, *forSpecial = NULL;
843    if (keyws) {
844        forDC = PyDict_GetItemString(keyws, "substitute_DC");
845        if (!forDC) {
846            forDC = PyDict_GetItemString(keyws, "substituteDC");
847        }
848        forDC = PyDict_GetItemString(keyws, "substitute_DK");
849        if (!forDC) {
850            forDC = PyDict_GetItemString(keyws, "substituteDK");
851        }
852        forDC = PyDict_GetItemString(keyws, "substitute_other");
853        if (!forDC) {
854            forDC = PyDict_GetItemString(keyws, "substituteOther");
855        }
856    }
857    return convertToPythonNative(PyExample_AS_ExampleReference(pex), natvt, tuples, forDK, forDC, forSpecial);
858  PyCATCH
859}
860
861
862PyObject *Example_checksum(TPyExample *pex, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
863{ return PyInt_FromLong(PyExample_AS_ExampleReference(pex).sumValues()); }
864
865
866#include "slist.hpp"
867
868void Example_pack(const TExample &example, TCharBuffer &buf, PyObject *&otherValues)
869{
870  for(TValue *vali = example.values; vali != example.classes_end; vali++)
871    Value_pack(*vali, buf, otherValues);
872
873  buf.writeInt(example.meta.size() | (example.name ? 1<<31 : 0));
874  buf.writeLong(example.id);
875
876  if (example.name) {
877    if (!otherValues)
878      otherValues = PyList_New(0);
879    PyObject *pyname = PyString_FromString(example.name->c_str());
880    PyList_Append(otherValues, pyname);
881    Py_DECREF(pyname);
882  }
883
884  const_ITERATE(TMetaValues, mi, example.meta) {
885    buf.writeInt((int)(mi->first));
886    buf.writeChar(mi->second.varType);
887    Value_pack(mi->second, buf, otherValues);
888  }
889}
890
891
892void Example_unpack(TExample &example, TCharBuffer &buf, PyObject *&otherValues, int &otherValuesIndex)
893{
894  TVarList::const_iterator vi;
895  TValue *vali = example.values;
896  for(vi = example.domain->variables->begin(); vali != example.values_end; vali++, vi++) {
897    vali->varType = (*vi)->varType;
898    Value_unpack(*vali, buf, otherValues, otherValuesIndex);
899  }
900  for(vi = example.domain->classVars->begin(); vali != example.classes_end; vali++, vi++) {
901    vali->varType = (*vi)->varType;
902    Value_unpack(*vali, buf, otherValues, otherValuesIndex);
903  }
904
905  int nMetas = buf.readInt();
906  example.id = buf.readLong();
907
908  if (nMetas & (1<<31)) {
909    PyObject *pyname = PyList_GetItem(otherValues, otherValuesIndex++);
910    example.name = new string(PyString_AsString(pyname));
911  }
912
913  for(int i = nMetas & 0x7fffffff; i--; ) {
914    const int id = buf.readInt();
915    TValue val((const unsigned char &)(buf.readChar()));
916    Value_unpack(val, buf, otherValues, otherValuesIndex);
917    example.meta.setValue(id, val);
918  }
919}
920
921
922PyObject *Example__reduce__(TPyExample *pex)
923{
924  PyTRY
925    if (pex->lock)
926      PYERROR(PyExc_TypeError, "examples that reference tables cannot be pickled", PYNULL);
927
928    TExample &example = PyExample_AS_ExampleReference(pex);
929
930    TCharBuffer buf(1024);
931    PyObject *otherValues = NULL;
932    Example_pack(example, buf, otherValues);
933    if (!otherValues) {
934      otherValues = Py_None;
935      Py_INCREF(otherValues);
936    }
937   
938    if (pex->example.counter->orange_dict)
939      return Py_BuildValue("O(Ns#N)O", getExportedFunction("__pickleLoaderExample"),
940                                      WrapOrange(example.domain),
941                                      buf.buf, buf.length(),
942                                      otherValues,
943                                      pex->example.counter->orange_dict);
944    else
945      return Py_BuildValue("O(Ns#N)", getExportedFunction("__pickleLoaderExample"),
946                                      WrapOrange(example.domain),
947                                      buf.buf, buf.length(),
948                                      otherValues);
949  PyCATCH
950}
951
952
953PyObject *__pickleLoaderExample(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(domain, packed_values, other_values)")
954{
955  PyTRY
956    PDomain domain;
957    char *pbuf;
958    int bufSize;
959    PyObject *otherValues;
960
961    if (!PyArg_ParseTuple(args, "O&s#O:__pickleLoaderExample", cc_Domain, &domain, &pbuf, &bufSize, &otherValues))
962      return NULL;
963
964    TExample *newEx = new TExample(domain);
965    PExample wex = newEx;
966    int otherValuesIndex = 0;
967
968    TCharBuffer buf(pbuf);
969    Example_unpack(*newEx, buf, otherValues, otherValuesIndex);
970    return Example_FromWrappedExample(wex);
971  PyCATCH
972}
973
974inline void addValue(string &res, const TValue &val, PVariable var)
975{ string str;
976  var->val2str(val, str);
977  if (var->varType!=TValue::FLOATVAR) res+="'"+str+"'";
978  else res+=str;
979}
980
981string TPyExample2string(TPyExample *pex)
982{ PExample example = PyExample_AS_Example(pex);
983  string res("[");
984  TVarList::iterator vi(example->domain->variables->begin());
985  TVarList::iterator ve(example->domain->variables->end());
986  TExample::const_iterator ei = example->values;
987  for(; vi != ve; vi++, ei++) {
988    if (ei != example->values)
989      res+=", ";
990    addValue(res, *ei, *vi);
991  }
992  res+="]";
993
994  vi = example->domain->classVars->begin();
995  ve = example->domain->classVars->end();
996  if (vi != ve) {
997      res += " (";
998      for(; vi != ve; vi++, ei++) {
999          if (ei != example->values_end)
1000              res += ", ";
1001          addValue(res, *ei, *vi);
1002      }
1003      res += ")";
1004  }
1005
1006  int madded=0;
1007  ITERATE(TMetaValues, mi, example->meta) {
1008    res+= (madded++) ? ", " : ", {";
1009   
1010    TMetaDescriptor *desc=example->domain->metas[(*mi).first];
1011    if (desc) {
1012      res+="\""+desc->variable->get_name()+"\":";
1013      addValue(res, (*mi).second, desc->variable);
1014    }
1015    else
1016      if ((*mi).second.varType==TValue::FLOATVAR) {
1017        char buf[128];
1018        sprintf(buf, "%i:%.2f", int((*mi).first), (*mi).second.floatV);
1019        res += buf;
1020      }
1021      else
1022        res+="???";
1023  }
1024
1025  if (madded) res+="}";
1026
1027  return res;
1028}
1029
1030PyObject *Example_repr(TPyExample *pex)
1031{ PyTRY
1032    return PyString_FromString(TPyExample2string(pex).c_str()); 
1033  PyCATCH
1034}
1035
1036PyObject *Example_str(TPyExample *pex)
1037{ PyTRY
1038    return PyString_FromString(TPyExample2string(pex).c_str()); 
1039  PyCATCH
1040}
1041
1042PyObject *Example_get_domain(TPyExample *self)
1043{ PyTRY
1044    return WrapOrange(PyExample_AS_Example(self)->domain);
1045  PyCATCH
1046}
1047
1048PyObject *Example_get_id(TPyExample *self)
1049{ PyTRY
1050    return PyInt_FromLong(PyExample_AS_Example(self)->id);
1051  PyCATCH
1052}
1053
1054PyObject *Example_newId(TPyExample *self)
1055{
1056  PyTRY
1057    PyExample_AS_Example(self)->id = getExampleId();
1058    RETURN_NONE;
1059  PyCATCH
1060}
1061
1062PyObject *richcmp_from_sign(const int &i, const int &op);
1063
1064PyObject *Example_richcmp(TPyExample *one, TPyExample *another, int op)
1065{ PyTRY
1066    if (!PyOrExample_Check(another)) {
1067        Py_INCREF(Py_NotImplemented);
1068        return Py_NotImplemented;
1069    }
1070
1071    PExample rone = PyExample_AS_Example(one);
1072    TExample &ranother = PyExample_AS_ExampleReference(another);
1073    if (rone->domain != ranother.domain) {
1074        if ((op == Py_EQ) || (op == Py_NE)) {
1075            PyObject *res = op == Py_NE ? Py_True : Py_False;
1076            Py_INCREF(res);
1077            return res;
1078        }
1079        else {
1080            PYERROR(PyExc_ValueError, "examples are from different domains", NULL);
1081        }
1082    }
1083    return richcmp_from_sign(rone->compare(ranother), op);
1084  PyCATCH
1085}
1086
1087
1088int Example_hash(TPyExample *ex)
1089{ PyTRY
1090    return PyExample_AS_Example(ex)->sumValues();
1091  PyCATCH_1
1092}
1093
1094
1095int Example_len(TPyExample *pex)
1096{ PyTRY
1097    return PyExample_AS_Example(pex)->domain->variables->size();
1098  PyCATCH_1
1099}
1100
1101
1102char *example_underscores[][2] = {
1103    {"getweight", "get_weight"},
1104    {"setweight", "set_weight"},
1105    {"removeweight", "remove_weight"},
1106    {"getmeta", "get_meta"},
1107    {"getmetas", "get_metas"},
1108    {"hasmetas", "has_meta"},
1109    {"setvalue", "set_value"},
1110    {"setmeta", "set_meta"},
1111    {"removemeta", "remove_meta"},
1112    {"getclass", "get_class"},
1113    {"setclass", "set_class"},
1114    {NULL, NULL}
1115};
1116
1117PyObject *Example_getattr(TPyExample *self, PyObject *name)
1118{
1119  char *orig = PyString_AsString(name);
1120  for(char *(*ei)[2] = example_underscores; **ei; ei++) {
1121      if (!strcmp(orig, **ei)) {
1122          PyObject *trans = PyString_FromString((*ei)[1]);
1123          PyObject *value = PyObject_GenericGetAttr((PyObject *)self, trans);
1124          Py_DECREF(trans);
1125          return value;
1126      }
1127  }
1128
1129  if (!PyString_Check(name) || strcmp(orig, "name"))
1130    return PyObject_GenericGetAttr((PyObject *)self, name);
1131
1132  const string *ename = self->example->name;
1133  return PyString_FromString(ename ? ename->c_str() : "");
1134}
1135
1136
1137int Example_setattr(TPyExample *self, PyObject *name, PyObject *text)
1138{
1139  if (!PyString_Check(name) || strcmp(PyString_AsString(name), "name"))
1140    return PyObject_GenericSetAttr((PyObject *)self, name, text);
1141
1142  string *&ename = self->example->name;
1143
1144  if (text == Py_None) {
1145    if (ename) {
1146      delete ename;
1147      ename = NULL;
1148    }
1149    return 0;
1150  }
1151
1152  if (PyString_Check(text)) {
1153    if (ename)
1154      delete ename;
1155    ename = new string(PyString_AsString(text));
1156    return 0;
1157  }
1158
1159  PYERROR(PyExc_AttributeError, "Example.name must be a string", -1);
1160}
1161
1162
1163extern PyTypeObject PyExampleIter_Type;
1164
1165class TPyExampleIter {
1166public:
1167  PyObject_HEAD
1168
1169  long index;
1170  TPyExample *example; /* Set to NULL when iterator is exhausted */
1171};
1172
1173PyObject *PyExampleIter_New(TPyExample *ex)
1174{
1175  TPyExampleIter *self = PyObject_GC_New(TPyExampleIter, &PyExampleIter_Type);
1176  if (self == NULL)
1177    return NULL;
1178
1179  self->index = 0;
1180
1181  Py_INCREF(ex);
1182    self->example = ex;
1183    PyObject_GC_Track(self);
1184    return (PyObject *)self;
1185}
1186
1187static void PyExampleIter_Dealloc(TPyExampleIter *self)
1188{
1189  PyObject_GC_UnTrack(self);
1190  Py_XDECREF(self->example);
1191  PyObject_GC_Del(self);
1192}
1193
1194static int PyExampleIter_Traverse(TPyExampleIter *self, visitproc visit, void *arg)
1195{
1196    return self->example ? visit((PyObject *)(self->example), arg) : 0;
1197}
1198
1199
1200int PyExampleIter_Clear(TPyExampleIter *self)
1201{ Py_XDECREF((PyObject *)(self->example));
1202  self->example = NULL;
1203  return 0;
1204}
1205
1206
1207static PyObject *PyExampleIter_Iternext(TPyExampleIter *self)
1208{
1209  if (!self->example)
1210    return NULL;
1211
1212  if (self->index >= PyExample_AS_ExampleReference(self->example).domain->variables->size()) {
1213    Py_DECREF(self->example);
1214    self->example = NULL;
1215    PYERROR(PyExc_StopIteration, "", PYNULL);
1216  }
1217
1218  TExample &ex = PyExample_AS_ExampleReference(self->example);
1219  PyObject *result = Value_FromVariableValue(ex.domain->getVar(self->index), ex[self->index]);
1220  self->index++;
1221  return result;
1222}
1223
1224
1225PyObject *PyExampleIter_Iter(PyObject *self)
1226{ Py_INCREF(self);
1227  return self;
1228}
1229
1230
1231PyTypeObject PyExampleIter_Type = {
1232    PyObject_HEAD_INIT(&PyType_Type)
1233    0,
1234    "orange.Example iterator",
1235    sizeof(TPyExampleIter),
1236    0,
1237    (destructor)PyExampleIter_Dealloc,
1238    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1239    PyObject_GenericGetAttr,
1240    0, 0,
1241    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1242    0,
1243    (traverseproc)PyExampleIter_Traverse,
1244    (inquiry)PyExampleIter_Clear, 0, 0,
1245    PyExampleIter_Iter,
1246    (iternextfunc)PyExampleIter_Iternext,
1247    0, 0, 0, 0, 0, 0, 0,
1248};
1249
1250
1251#include "cls_example.px"
Note: See TracBrowser for help on using the repository browser.