source: orange/source/orange/cls_example.cpp @ 9415:b8c964fe3d51

Revision 9415:b8c964fe3d51, 34.0 KB checked in by janezd <janez.demsar@…>, 2 years ago (diff)

Fixed multiple classes: pickling, conversion between domains, printing

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