source: orange/source/orange/cls_example.cpp @ 7665:3aede63f569f

Revision 7665:3aede63f569f, 32.2 KB checked in by markotoplak, 3 years ago (diff)

Replaced Variable->name with setter and getter. Interface to Python remained the same.

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, 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_set_class(TPyExample *pex, PyObject *val) PYARGS(METH_O, "(value); Sets example's class")
597{ PyTRY
598    PExample &example=PyExample_AS_Example(pex);
599    PVariable &classVar = example->domain->classVar;
600
601    if (!classVar)
602      PYERROR(PyExc_SystemError, "classless domain", PYNULL);
603
604    TValue value;
605    if (!convertFromPython(val, value, classVar)) 
606      return PYNULL;
607    example->setClass(value);
608
609    RETURN_NONE;
610  PyCATCH
611}
612
613
614PyObject *Example_compatible(TPyExample *pex, PyObject *args) PYARGS(METH_VARARGS, "(example[, ignoreClass]); Returns true if examples are compatible")
615{ PyTRY
616    PExample example;
617    int ic = 0;
618    if (!PyArg_ParseTuple(args, "O&|i", cc_Example, &example, &ic))
619      PYERROR(PyExc_TypeError, "example and, optionally, a flag for ignoring the class expected", PYNULL)
620
621    return PyInt_FromLong(PyExample_AS_Example(pex)->compatible(example.getReference(), ic != 0) ? 1 : 0);
622  PyCATCH
623}
624
625
626PyObject *PyExampleIter_New(TPyExample *);
627
628PyObject *Example_iter(TPyExample *pex)
629{ return PyExampleIter_New(pex);
630}
631
632
633int getAttributeIndex(PDomain domain, PyObject *vara)
634{
635    if (PyInt_Check(vara)) {
636      int ind = int(PyInt_AsLong(vara));
637      if (ind >= (int)(domain->variables->size())) {
638        PyErr_Format(PyExc_IndexError, "index %i to large (> %i)", ind, domain->variables->size()-1);
639        return ILLEGAL_INT;
640      }
641
642      // Exception: example[-1] gives class value
643      return ind==-1 ? domain->variables->size()-1 : ind;
644    }
645
646    PVariable var=varFromArg_byDomain(vara, domain);
647    if (!var) 
648      PYERROR(PyExc_TypeError, "invalid arguments or unknown attribute name", ILLEGAL_INT);
649
650    return domain->getVarNum(var);
651}
652
653
654PyObject *Example_getitem(TPyExample *pex, PyObject *vara)
655{ PyTRY
656    PExample example = PyExample_AS_Example(pex);
657
658    int ind = getAttributeIndex(example->domain, vara);
659    if (ind==ILLEGAL_INT)
660      return PYNULL;
661
662    if ((ind < 0) && !example->hasMeta(ind)) {
663      TMetaDescriptor *metadesc = example->domain->metas[ind];
664      if (metadesc && metadesc->optional)
665        return Value_FromVariableValue(metadesc->variable, metadesc->variable->DK());
666    }
667   
668    /* getVar will return NULL if ind is meta-attribute not registered with the domain.
669       That's OK - we don't need PVariable (Value_FromValue would do exactly the same).
670       operator[] will raise an exception if meta-value is requested and the example
671       doesn't have it. */
672    return Value_FromVariableValue(example->domain->getVar(ind, false), example->operator[](ind));
673  PyCATCH
674}
675
676
677int Example_setitem(TPyExample *pex, PyObject *vara, PyObject *vala)
678{ PyTRY
679    PExample example = PyExample_AS_Example(pex);
680    const int ind = getAttributeIndex(example->domain, vara);
681    if (ind==ILLEGAL_INT)
682      return -1;
683
684    PVariable var = example->domain->getVar(ind, false);
685
686    if (PyOrValue_Check(vala)) {
687      if (PyValue_AS_Variable(vala) && var && (PyValue_AS_Variable(vala)!=var)) {
688          string vals;
689          PyValue_AS_Variable(vala)->val2str(PyValue_AS_Value(vala), vals);
690          if (ind>=0)
691            var->str2val(vals, example->operator[](ind));
692          else {
693            TValue val;
694            var->str2val(vals, val);
695            example->setMeta(ind, val);
696          }
697        }
698      else {
699        if (ind>=0)
700          example->operator[](ind) = PyValue_AS_Value(vala);
701        else
702          example->setMeta(ind, PyValue_AS_Value(vala));
703      }
704    }
705
706    else {
707      TValue value;
708      if (!convertFromPython(vala, value, var)) 
709        return -1;
710      if (ind>=0)
711        example->operator[](ind) = value;
712      else
713        example->setMeta(ind, value);
714    }
715
716    return 0;
717
718  PyCATCH_1
719}
720
721
722
723inline PyObject *toValue(const TValue &val, PVariable var, int natvt, PyObject *forDK, PyObject *forDC, PyObject *forSpecial)
724{ switch (natvt) {
725    case -1:
726      return (val.varType==TValue::INTVAR)
727            ? PyInt_FromLong(long(val.intV))
728            : PyFloat_FromDouble(double(val.floatV));
729
730    case  0:
731      if (val.isSpecial()) {
732        PyObject *res;
733        if (val.isDC())
734          res = forDC;
735        else if (val.isDK())
736          res = forDK;
737        else
738          res = forSpecial;
739        Py_INCREF(res);
740        return res;
741      }   
742      else
743        return convertToPythonNative(val, var);
744
745    default:
746      return Value_FromVariableValue(var, val);
747  }
748}
749
750PyObject *convertToPythonNative(const TExample &example, int natvt, bool tuples, PyObject *forDK, PyObject *forDC, PyObject *forSpecial)
751{
752  if (forDK)
753    Py_INCREF(forDK);
754  else
755    forDK = PyString_FromString("?");
756
757  if (forDC)
758    Py_INCREF(forDC);
759  else
760    forDC = PyString_FromString("~");
761
762  if (forSpecial)
763    Py_INCREF(forSpecial);
764  else
765    forSpecial = PyString_FromString(".");
766
767  PyObject *list=PyList_New(0);
768  TExample::const_iterator ei=example.begin();
769  const_PITERATE(TVarList, vi, example.domain->attributes) {
770    PyObject *valo = toValue(*(ei++), *vi, natvt, forDK, forDC, forSpecial);
771    PyList_Append(list, valo);
772    Py_DECREF(valo);
773  }
774
775  PyObject *res;
776
777  if (example.domain->classVar) {
778    PyObject *pyclass = toValue(example.getClass(), example.domain->classVar, natvt, forDK, forDC, forSpecial);
779    if (tuples)
780      res = Py_BuildValue("NN", list, pyclass);
781    else {
782      PyList_Append(list, pyclass);
783      Py_DECREF(pyclass);
784      res = list;
785    }
786  }
787   
788  else {
789    if (tuples)
790      res = Py_BuildValue("NO", list, Py_None);
791    else
792      res = list;
793  }
794
795  Py_DECREF(forDK);
796  Py_DECREF(forDC);
797  Py_DECREF(forSpecial);
798
799  return res;
800}
801
802
803PyObject *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")
804{ PyTRY
805    int natvt=1;
806    if (args && !PyArg_ParseTuple(args, "|i", &natvt))
807      PYERROR(PyExc_TypeError, "invalid arguments (no arguments or an integer expected)", PYNULL);
808
809    bool tuples = false;
810    PyObject *pytuples = keyws ? PyDict_GetItemString(keyws, "tuple") : PYNULL;
811    tuples = pytuples && (PyObject_IsTrue(pytuples) != 0);
812
813    PyObject *forDC = NULL, *forDK = NULL, *forSpecial = NULL;
814    if (keyws) {
815        forDC = PyDict_GetItemString(keyws, "substitute_DC");
816        if (!forDC) {
817            forDC = PyDict_GetItemString(keyws, "substituteDC");
818        }
819        forDC = PyDict_GetItemString(keyws, "substitute_DK");
820        if (!forDC) {
821            forDC = PyDict_GetItemString(keyws, "substituteDK");
822        }
823        forDC = PyDict_GetItemString(keyws, "substitute_other");
824        if (!forDC) {
825            forDC = PyDict_GetItemString(keyws, "substituteOther");
826        }
827    }
828    return convertToPythonNative(PyExample_AS_ExampleReference(pex), natvt, tuples, forDK, forDC, forSpecial);
829  PyCATCH
830}
831
832
833PyObject *Example_checksum(TPyExample *pex, PyObject *) PYARGS(METH_NOARGS, "() -> crc")
834{ return PyInt_FromLong(PyExample_AS_ExampleReference(pex).sumValues()); }
835
836
837#include "slist.hpp"
838
839void Example_pack(const TExample &example, TCharBuffer &buf, PyObject *&otherValues)
840{
841  for(TValue *vali = example.values; vali != example.values_end; vali++)
842    Value_pack(*vali, buf, otherValues);
843
844  buf.writeInt(example.meta.size() | (example.name ? 1<<31 : 0));
845  buf.writeLong(example.id);
846
847  if (example.name) {
848    if (!otherValues)
849      otherValues = PyList_New(0);
850    PyObject *pyname = PyString_FromString(example.name->c_str());
851    PyList_Append(otherValues, pyname);
852    Py_DECREF(pyname);
853  }
854
855  const_ITERATE(TMetaValues, mi, example.meta) {
856    buf.writeInt((int)(mi->first));
857    buf.writeChar(mi->second.varType);
858    Value_pack(mi->second, buf, otherValues);
859  }
860}
861
862
863void Example_unpack(TExample &example, TCharBuffer &buf, PyObject *&otherValues, int &otherValuesIndex)
864{
865  TVarList::const_iterator vi = example.domain->variables->begin();
866  for(TValue *vali = example.values; vali != example.values_end; vali++, vi++) {
867    vali->varType = (*vi)->varType;
868    Value_unpack(*vali, buf, otherValues, otherValuesIndex);
869  }
870
871  int nMetas = buf.readInt();
872  example.id = buf.readLong();
873
874  if (nMetas & (1<<31)) {
875    PyObject *pyname = PyList_GetItem(otherValues, otherValuesIndex++);
876    example.name = new string(PyString_AsString(pyname));
877  }
878
879  for(int i = nMetas & 0x7fffffff; i--; ) {
880    const int id = buf.readInt();
881    TValue val((const unsigned char &)(buf.readChar()));
882    Value_unpack(val, buf, otherValues, otherValuesIndex);
883    example.meta.setValue(id, val);
884  }
885}
886
887
888PyObject *Example__reduce__(TPyExample *pex)
889{
890  PyTRY
891    if (pex->lock)
892      PYERROR(PyExc_TypeError, "examples that reference tables cannot be pickled", PYNULL);
893
894    TExample &example = PyExample_AS_ExampleReference(pex);
895
896    TCharBuffer buf(1024);
897    PyObject *otherValues = NULL;
898    Example_pack(example, buf, otherValues);
899    if (!otherValues) {
900      otherValues = Py_None;
901      Py_INCREF(otherValues);
902    }
903   
904    if (pex->example.counter->orange_dict)
905      return Py_BuildValue("O(Ns#N)O", getExportedFunction("__pickleLoaderExample"),
906                                      WrapOrange(example.domain),
907                                      buf.buf, buf.length(),
908                                      otherValues,
909                                      pex->example.counter->orange_dict);
910    else
911      return Py_BuildValue("O(Ns#N)", getExportedFunction("__pickleLoaderExample"),
912                                      WrapOrange(example.domain),
913                                      buf.buf, buf.length(),
914                                      otherValues);
915  PyCATCH
916}
917
918
919PyObject *__pickleLoaderExample(PyObject *, PyObject *args) PYARGS(METH_VARARGS, "(domain, packed_values, other_values)")
920{
921  PyTRY
922    PDomain domain;
923    char *pbuf;
924    int bufSize;
925    PyObject *otherValues;
926
927    if (!PyArg_ParseTuple(args, "O&s#O:__pickleLoaderExample", cc_Domain, &domain, &pbuf, &bufSize, &otherValues))
928      return NULL;
929
930    TExample *newEx = new TExample(domain);
931    PExample wex = newEx;
932    int otherValuesIndex = 0;
933
934    TCharBuffer buf(pbuf);
935    Example_unpack(*newEx, buf, otherValues, otherValuesIndex);
936    return Example_FromWrappedExample(wex);
937  PyCATCH
938}
939
940inline void addValue(string &res, const TValue &val, PVariable var)
941{ string str;
942  var->val2str(val, str);
943  if (var->varType!=TValue::FLOATVAR) res+="'"+str+"'";
944  else res+=str;
945}
946
947string TPyExample2string(TPyExample *pex)
948{ PExample example = PyExample_AS_Example(pex);
949  string res("[");
950  TVarList::iterator vi(example->domain->variables->begin());
951  PITERATE(TExample, ei, example) {
952    if (ei!=example->begin())
953      res+=", ";
954    addValue(res, *ei, *(vi++));
955  }
956  res+="]";
957
958  int madded=0;
959  ITERATE(TMetaValues, mi, example->meta) {
960    res+= (madded++) ? ", " : ", {";
961   
962    TMetaDescriptor *desc=example->domain->metas[(*mi).first];
963    if (desc) {
964      res+="\""+desc->variable->get_name()+"\":";
965      addValue(res, (*mi).second, desc->variable);
966    }
967    else
968      if ((*mi).second.varType==TValue::FLOATVAR) {
969        char buf[128];
970        sprintf(buf, "%i:%.2f", int((*mi).first), (*mi).second.floatV);
971        res += buf;
972      }
973      else
974        res+="???";
975  }
976
977  if (madded) res+="}";
978
979  return res;
980}
981
982PyObject *Example_repr(TPyExample *pex)
983{ PyTRY
984    return PyString_FromString(TPyExample2string(pex).c_str()); 
985  PyCATCH
986}
987
988PyObject *Example_str(TPyExample *pex)
989{ PyTRY
990    return PyString_FromString(TPyExample2string(pex).c_str()); 
991  PyCATCH
992}
993
994PyObject *Example_get_domain(TPyExample *self)
995{ PyTRY
996    return WrapOrange(PyExample_AS_Example(self)->domain);
997  PyCATCH
998}
999
1000PyObject *Example_get_id(TPyExample *self)
1001{ PyTRY
1002    return PyInt_FromLong(PyExample_AS_Example(self)->id);
1003  PyCATCH
1004}
1005
1006PyObject *Example_newId(TPyExample *self)
1007{
1008  PyTRY
1009    PyExample_AS_Example(self)->id = getExampleId();
1010    RETURN_NONE;
1011  PyCATCH
1012}
1013
1014int Example_cmp(TPyExample *one, TPyExample *another)
1015{ PyTRY
1016    return PyExample_AS_Example(one)->compare(PyExample_AS_ExampleReference(another));
1017  PyCATCH_1
1018}
1019
1020
1021int Example_hash(TPyExample *ex)
1022{ PyTRY
1023    return PyExample_AS_Example(ex)->sumValues();
1024  PyCATCH_1
1025}
1026
1027
1028int Example_len(TPyExample *pex)
1029{ PyTRY
1030    return PyExample_AS_Example(pex)->domain->variables->size();
1031  PyCATCH_1
1032}
1033
1034
1035char *example_underscores[][2] = {
1036    {"getweight", "get_weight"},
1037    {"setweight", "set_weight"},
1038    {"removeweight", "remove_weight"},
1039    {"getmeta", "get_meta"},
1040    {"getmetas", "get_metas"},
1041    {"hasmetas", "has_meta"},
1042    {"setvalue", "set_value"},
1043    {"setmeta", "set_meta"},
1044    {"removemeta", "remove_meta"},
1045    {"getclass", "get_class"},
1046    {"setclass", "set_class"},
1047    {NULL, NULL}
1048};
1049
1050PyObject *Example_getattr(TPyExample *self, PyObject *name)
1051{
1052  char *orig = PyString_AsString(name);
1053  for(char *(*ei)[2] = example_underscores; **ei; ei++) {
1054      if (!strcmp(orig, **ei)) {
1055          PyObject *trans = PyString_FromString((*ei)[1]);
1056          PyObject *value = PyObject_GenericGetAttr((PyObject *)self, trans);
1057          Py_DECREF(trans);
1058          return value;
1059      }
1060  }
1061
1062  if (!PyString_Check(name) || strcmp(orig, "name"))
1063    return PyObject_GenericGetAttr((PyObject *)self, name);
1064
1065  const string *ename = self->example->name;
1066  return PyString_FromString(ename ? ename->c_str() : "");
1067}
1068
1069
1070int Example_setattr(TPyExample *self, PyObject *name, PyObject *text)
1071{
1072  if (!PyString_Check(name) || strcmp(PyString_AsString(name), "name"))
1073    return PyObject_GenericSetAttr((PyObject *)self, name, text);
1074
1075  string *&ename = self->example->name;
1076
1077  if (text == Py_None) {
1078    if (ename) {
1079      delete ename;
1080      ename = NULL;
1081    }
1082    return 0;
1083  }
1084
1085  if (PyString_Check(text)) {
1086    if (ename)
1087      delete ename;
1088    ename = new string(PyString_AsString(text));
1089    return 0;
1090  }
1091
1092  PYERROR(PyExc_AttributeError, "Example.name must be a string", -1);
1093}
1094
1095
1096extern PyTypeObject PyExampleIter_Type;
1097
1098class TPyExampleIter {
1099public:
1100  PyObject_HEAD
1101
1102  long index;
1103  TPyExample *example; /* Set to NULL when iterator is exhausted */
1104};
1105
1106PyObject *PyExampleIter_New(TPyExample *ex)
1107{
1108  TPyExampleIter *self = PyObject_GC_New(TPyExampleIter, &PyExampleIter_Type);
1109  if (self == NULL)
1110    return NULL;
1111
1112  self->index = 0;
1113
1114  Py_INCREF(ex);
1115    self->example = ex;
1116    PyObject_GC_Track(self);
1117    return (PyObject *)self;
1118}
1119
1120static void PyExampleIter_Dealloc(TPyExampleIter *self)
1121{
1122  PyObject_GC_UnTrack(self);
1123  Py_XDECREF(self->example);
1124  PyObject_GC_Del(self);
1125}
1126
1127static int PyExampleIter_Traverse(TPyExampleIter *self, visitproc visit, void *arg)
1128{
1129    return self->example ? visit((PyObject *)(self->example), arg) : 0;
1130}
1131
1132
1133int PyExampleIter_Clear(TPyExampleIter *self)
1134{ Py_XDECREF((PyObject *)(self->example));
1135  self->example = NULL;
1136  return 0;
1137}
1138
1139
1140static PyObject *PyExampleIter_Iternext(TPyExampleIter *self)
1141{
1142  if (!self->example)
1143    return NULL;
1144
1145  if (self->index >= PyExample_AS_ExampleReference(self->example).domain->variables->size()) {
1146    Py_DECREF(self->example);
1147    self->example = NULL;
1148    PYERROR(PyExc_StopIteration, "", PYNULL);
1149  }
1150
1151  TExample &ex = PyExample_AS_ExampleReference(self->example);
1152  PyObject *result = Value_FromVariableValue(ex.domain->getVar(self->index), ex[self->index]);
1153  self->index++;
1154  return result;
1155}
1156
1157
1158PyObject *PyExampleIter_Iter(PyObject *self)
1159{ Py_INCREF(self);
1160  return self;
1161}
1162
1163
1164PyTypeObject PyExampleIter_Type = {
1165    PyObject_HEAD_INIT(&PyType_Type)
1166    0,
1167    "orange.Example iterator",
1168    sizeof(TPyExampleIter),
1169    0,
1170    (destructor)PyExampleIter_Dealloc,
1171    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1172    PyObject_GenericGetAttr,
1173    0, 0,
1174    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1175    0,
1176    (traverseproc)PyExampleIter_Traverse,
1177    (inquiry)PyExampleIter_Clear, 0, 0,
1178    PyExampleIter_Iter,
1179    (iternextfunc)PyExampleIter_Iternext,
1180    0, 0, 0, 0, 0, 0, 0,
1181};
1182
1183
1184#include "cls_example.px"
Note: See TracBrowser for help on using the repository browser.