source: orange/source/orange/cls_example.cpp @ 11697:49d2a5f5db16

Revision 11697:49d2a5f5db16, 35.4 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Check the values of discrete features in Orange.data.Table constructor.

(references #1322)

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