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

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

Removed the GPL copyright notice from all files except orangeqt.

Line 
1#include <string.h>
2
3#include "stladdon.hpp"
4
5#include "vars.hpp"
6#include "domain.hpp"
7
8#include "cls_value.hpp"
9#include "cls_example.hpp"
10#include "cls_orange.hpp"
11
12#include "externs.px"
13
14
15BASED_ON(Orange, ROOT)
16DATASTRUCTURE(Orange - Orange.core.OrangeBase, TPyOrange, orange_dict)
17RECOGNIZED_ATTRIBUTES(Orange, "name shortDescription description")
18
19
20PyObject *PyOrType_GenericAbstract(PyTypeObject *thistype, PyTypeObject *type, PyObject *args, PyObject *kwds)
21{ PyTRY
22    // if the user wants to create an instance of abstract class, we stop him
23    if ((thistype == type) || !thistype->tp_base || !thistype->tp_base->tp_new) {
24      PyErr_Format(PyExc_TypeError,  "cannot create instances of abstract class '%s'", type->tp_name);
25      return NULL;
26    }
27
28    // if he derived a new class, we may let him
29    return thistype->tp_base->tp_new(type, args, kwds);
30  PyCATCH
31}
32
33
34PyObject *PyOrType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *)
35{ PyTRY
36    PyObject *old = NULL;
37    if (args && !PyArg_ParseTuple(args, "|O", &old)) {
38      PyErr_Format(PyExc_TypeError, "%s: invalid arguments: nothing or an existing object expected", type->tp_name);
39      return NULL;
40    }
41
42    if (old)
43      if (PyType_IsSubtype(old->ob_type, type)) {
44        Py_INCREF(old);
45        return old;
46      }
47      else {
48        PyErr_Format(PyExc_TypeError, "%s: '%s' is not a subtype of '%s'", type->tp_name, old->ob_type->tp_name, type->tp_name);
49        return NULL;
50      }
51
52    // we assert PyOrange_OrangeBaseClass will succeed and that ot_defaultconstruct is defined.
53    // the latter is pyxtract responsibility and pyxtract shouldn't be doubted  ;)
54    POrange obj = PyOrange_OrangeBaseClass(type)->ot_defaultconstruct(type);
55    if (!obj) {
56      PyErr_Format(PyExc_SystemError, "constructor for '%s' failed", type->tp_name);
57      return NULL;
58    }
59     
60    return WrapOrange(obj);
61  PyCATCH
62}
63
64
65PyObject *PyOrType_GenericNamedNew(PyTypeObject *type, PyObject *args, PyObject *)
66{
67  PyTRY
68    PyObject *name=NULL;
69    if (args && !PyArg_ParseTuple(args, "|O", &name)) {
70      PyErr_Format(PyExc_TypeError, "%s: invalid arguments: nothing, a name or an existing object expected", type->tp_name);
71      return NULL;
72    }
73
74    if (name && !PyString_Check(name))
75      if (PyType_IsSubtype(name->ob_type, type)) {
76        Py_INCREF(name);
77        return name;
78      }
79      else {
80        PyErr_Format(PyExc_TypeError, "%s: '%s' is not a subtype of '%s'", type->tp_name, name->ob_type->tp_name, type->tp_name);
81        return NULL;
82      }
83
84    // we assert PyOrange_OrangeBaseClass will succeed and that ot_defaultconstruct is defined.
85    // the latter is pyxtract responsibility and pyxtract shouldn't be doubted
86    POrange obj = PyOrange_OrangeBaseClass(type)->ot_defaultconstruct(type);
87    if (!obj) {
88      PyErr_Format(PyExc_SystemError, "constructor for '%s' failed", type->tp_name);
89      return NULL;
90    }
91     
92    PyObject *self=WrapOrange(obj);
93
94    if (!name || (PyObject_SetAttrString(self, "name", name)==0))
95      return self;
96    else {
97      Py_DECREF(self);
98      return PYNULL;
99    }
100  PyCATCH
101}
102
103
104int Orange_init(PyObject *self, PyObject *args, PyObject *keywords);
105
106
107// Rewrapping: this is not a toy - use it cautiously
108void rewrap(TPyOrange *&obj, PyTypeObject *type)
109{ if (obj && (type!=obj->ob_type)) {
110    if (obj->ob_refcnt>1) {
111      #ifdef _MSC_VER
112        throw exception("cannot rewrap (refcnt>1)");
113      #else
114        throw exception();
115      #endif
116    }
117    PyObject_GC_UnTrack((PyObject *)obj);
118
119    TPyOrange *newobj = (TPyOrange *)type->tp_alloc(type, 0);
120    newobj->orange_dict = obj->orange_dict;
121    newobj->ptr = obj->ptr;
122    newobj->call_constructed = obj->call_constructed;
123    newobj->is_reference = obj->is_reference;
124
125    obj->orange_dict = NULL;
126    obj->ptr = NULL;
127    obj->freeRef();
128
129    obj = newobj;
130  }
131}
132
133
134PyObject *PyOrType_GenericCallableNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
135{ PyObject *self1 = NULL,
136           *self2 = NULL,
137           *ccReturn = NULL;
138
139  PyTRY
140  // we assert PyOrange_OrangeBaseClass will succeed and that ot_defaultconstruct is defined.
141  // the latter is pyxtract responsibility and pyxtract shouldn't be doubted
142    POrange obj=PyOrange_OrangeBaseClass(type)->ot_defaultconstruct(PyTuple_Size(args) ? (PyTypeObject *)&PyOrOrange_Type : type);
143    if (!obj) {
144      PyErr_Format(PyExc_SystemError, "constructor for '%s' failed", type->tp_name);
145      goto err;
146    }
147
148    PyObject *self1 = WrapOrange(obj);
149
150    if (!PyTuple_Size(args))
151      return self1;
152
153    else {
154/*      if (self1->ob_type != type) {
155        PyErr_Format(PyExc_SystemError, "Subclassed orange classes are not call-constructable", type->tp_name);
156        Py_DECREF(self1);
157        return NULL;
158      }
159*/
160      if (!self1->ob_type->tp_call) {
161        PyErr_Format(PyExc_SystemError, "error in orange class structure ('%s' not callable)", type->tp_name);
162        goto err;
163      }
164
165      /* We should manually call init - Python will call init on self2, and it won't do anything.
166         It's important to call it prior to setting call_constructed (below) */
167      if (Orange_init(self1, args, kwds) < 0)
168        goto err;
169
170      /* this is to tell tp_call(self1) not to complain about keyword arguments;
171         self1 is disposed later in this function, so this should cause no problems */
172      ((TPyOrange *)self1)->call_constructed = true;
173      PyObject *self2=self1->ob_type->tp_call(self1, args, kwds);
174
175      if (self2) {
176        if (type!=self1->ob_type) {
177          char *oname = new char[30 + strlen(type->tp_name)];
178          sprintf(oname, "_%s__call_construction_type", type->tp_name);
179          PyObject *ccReturn = PyObject_GetAttrString((PyObject *)type, oname);
180          delete oname;
181
182          if (!ccReturn) {
183            PyErr_Format(PyExc_SystemError, "no return type specified for call-construction of '%s'", type->tp_name);
184            goto err;
185          }
186
187          if (!PyType_Check(ccReturn)) {
188            PyErr_Format(PyExc_SystemError, "no return type specified for call-construction of '%s'", type->tp_name);
189            goto err;
190          }
191
192          if (self2->ob_refcnt>1) { // Object might have a reference to itself...
193            PyErr_Format(PyExc_SystemError, "cannot rewrap the class '%s' - too many references", self2->ob_type->tp_name);
194            goto err;
195          }
196
197          rewrap((TPyOrange *&)self2, (PyTypeObject *)ccReturn);
198        }
199
200        Py_DECREF(self1);
201
202        if (PyOrOrange_Check(self2))
203          ((TPyOrange *)self2)->call_constructed = true;
204        return self2;
205      }
206   
207    }
208  PyCATCH
209
210err:
211  Py_XDECREF(self1);
212  Py_XDECREF(self2);
213  Py_XDECREF(ccReturn);
214  return NULL;
215}
216
217
218int Orange_traverse(TPyOrange *self, visitproc visit, void *arg)
219{
220  if (self->orange_dict) {
221    int err = visit(self->orange_dict, arg);
222    if (err)
223      return err;
224  }
225
226  return ((TOrange *)self->ptr)->traverse(visit, arg);
227}
228
229
230int Orange_clear(TPyOrange *self)
231{ 
232  return ((TOrange *)self->ptr)->dropReferences();
233}
234
235
236PyObject *PyOrange__dict__(TPyOrange *self)
237{ 
238  if (!self->orange_dict)
239    self->orange_dict = PyOrange_DictProxy_New(self);
240
241  Py_INCREF(self->orange_dict);
242  return (PyObject *)(self->orange_dict);
243}
244
245
246PyObject *PyOrange__members__(TPyOrange *self)
247{
248  const TPropertyDescription *ppd = PyOrange_AS_Orange(self)->classDescription()->properties;
249  const TPropertyDescription *pd;
250  for(pd = ppd; pd->name; pd++);
251
252  PyObject *res = PyList_New(pd-ppd);
253  for(pd = ppd; pd->name; pd++)
254    PyList_SetItem(res, pd-ppd, PyString_FromString(pd->name));
255
256  return res;
257}
258
259
260char *camel2underscore(const char *camel)
261{
262    const char *ci = camel;
263    if ((*ci >= 'A') && (*ci <= 'Z')) {
264        return NULL;
265    }
266
267    char *underscored = (char *)malloc(2*strlen(camel)+1);
268    char *ui = underscored;
269    bool changed = false;
270    *ui = *ci;
271    while(*ci) { // just copied
272        if (   (*ci >= 'a') && (*ci <= 'z')       // a small letter
273            && (ci[1] >= 'A') && (ci[1] <= 'Z')) {  // followed by capital
274            *++ui = '_';
275            const char of = (ci[2] < 'A') || (ci[2] > 'Z') ? 32 : 0; // 32, if not followed by capital
276            *++ui = *++ci + of;
277            changed = true;
278        }
279        else {
280            *++ui = *++ci;
281        }
282    }
283    if (!changed) {
284        free(underscored);
285        underscored = NULL;
286    }
287    return underscored;
288}
289
290
291PyObject *PyOrange_translateObsolete(PyObject *self, PyObject *pyname)
292{ 
293  char *name = PyString_AsString(pyname);
294  char *underscored = camel2underscore(name);
295  for(TOrangeType *selftype = PyOrange_OrangeBaseClass(self->ob_type); PyOrange_CheckType((PyTypeObject *)selftype); selftype=(TOrangeType *)(selftype->ot_inherited.tp_base)) {
296      if (selftype->ot_aliases) {
297          for(TAttributeAlias *aliases=selftype->ot_aliases; aliases->alias; aliases++) {
298              if (!strcmp(name, aliases->alias) || (underscored && !strcmp(underscored, aliases->alias))) {
299                  if (underscored) {
300                      free(underscored);
301                  }
302                  return PyString_FromString(aliases->realName);
303              }
304          }
305      }
306  }
307  if (underscored) {
308      free(underscored);
309  }
310  return NULL;
311}   
312
313
314PyObject *Orange_getattr1(TPyOrange *self, const char *name)
315// This is a getattr, without translation of obsolete names and without looking into the associated dictionary
316{ PyTRY
317    if (!self)
318      PYERROR(PyExc_SystemError, "NULL Orange object", PYNULL);
319
320    TOrange *me = (TOrange *)self->ptr;
321    if (me->hasProperty(name)) {
322      try {
323        const TPropertyDescription *propertyDescription = me->propertyDescription(name);
324        const type_info &propertyType = *propertyDescription->type;
325        TPropertyTransformer *transformer = propertyDescription->transformer;
326
327        if (propertyType==typeid(bool)) {
328          bool value;
329          me->getProperty(name, value);
330          return transformer ? (PyObject *)transformer(&value) : PyBool_FromLong(value ? 1 : 0);
331        }
332
333        if (propertyType==typeid(int)) {
334          int value;
335          me->getProperty(name, value);
336          return transformer ? (PyObject *)transformer(&value) : PyInt_FromLong(value);
337        }
338
339        if (propertyType==typeid(float)) {
340          float value;
341          me->getProperty(name, value);
342          return transformer ? (PyObject *)transformer(&value) : PyFloat_FromDouble(value);
343        }
344
345        if (propertyType==typeid(string)) {
346          string value;
347          me->getProperty(name, value);
348          return transformer ? (PyObject *)transformer(&value) : PyString_FromString(value.c_str());
349        }
350
351        if (propertyType==typeid(TValue)) {
352          TValue value;
353          me->getProperty(name, value);
354          return transformer ? (PyObject *)transformer(&value) : Value_FromValue(value);
355        }
356
357        if (propertyType==typeid(TExample)) {
358          POrange mlobj;
359          me->wr_getProperty(name, mlobj);
360          if (transformer)
361            return (PyObject *)transformer(&mlobj);
362          if (mlobj)
363            return Example_FromWrappedExample(PExample(mlobj));
364          RETURN_NONE;
365        }
366     
367        POrange mlobj;
368        me->wr_getProperty(name, mlobj);
369        return transformer ? (PyObject *)transformer(&mlobj) : (PyObject *)WrapOrange(mlobj);
370      } catch (exception err)
371      {}
372    }
373 
374    PyErr_Format(PyExc_AttributeError, "'%s' has no attribute '%s'", self->ob_type->tp_name, name);
375    return PYNULL;
376  PyCATCH;
377}
378
379
380
381
382PyObject *Orange_getattr1(TPyOrange *self, PyObject *pyname)
383// This is a complete getattr, but without translation of obsolete names.
384{ PyTRY
385    if (!self)
386      PYERROR(PyExc_SystemError, "NULL Orange object", PYNULL);
387
388    if (self->orange_dict) {
389      PyObject *res = PyDict_GetItem(self->orange_dict, pyname);
390      if (res) {
391        Py_INCREF(res);
392        return res;
393      }
394    }
395     
396    PyObject *res = PyObject_GenericGetAttr((PyObject *)self, pyname);
397    if (res)
398      return res;
399
400    PyErr_Clear();
401
402    if (!PyString_Check(pyname))
403      PYERROR(PyExc_TypeError, "object's attribute name must be a string", PYNULL);
404    char *name=PyString_AsString(pyname);
405
406    if (strcmp(name, "__dict__") == 0)
407      return PyOrange__dict__(self);
408
409    if (strcmp(name, "__members__") == 0)
410      return PyOrange__members__(self);
411
412    if (strcmp(name, "__class__") == 0) {
413      Py_INCREF(self->ob_type);
414      return (PyObject *)self->ob_type;
415    }
416
417    return Orange_getattr1(self, name);
418  PyCATCH;
419}
420
421
422inline void PyDict_SIS_Steal(PyObject *dict, const char *name, PyObject *obj) {
423  PyDict_SetItemString(dict, name, obj);
424  Py_DECREF(obj);
425}
426
427PyObject *packOrangeDictionary(PyObject *self)
428{
429  PyTRY
430    PyObject *packed = ((TPyOrange *)self)->orange_dict ? PyDict_Copy(((TPyOrange *)self)->orange_dict) : PyDict_New();
431
432    TOrange *me = (TOrange *)((TPyOrange *)self)->ptr;
433
434    for (const TPropertyDescription *pd = me->classDescription()->properties; pd->name; pd++) {
435      if (!pd->readOnly) {
436 
437  //      const type_info &propertyType = pd->type;
438
439        if (pd->type == &typeid(bool))
440          PyDict_SIS_Steal(packed, pd->name, PyInt_FromLong(me->getProperty_bool(pd) ? 1 : 0));
441
442        else if (pd->type == &typeid(int))
443          PyDict_SIS_Steal(packed, pd->name, PyInt_FromLong(me->getProperty_int(pd)));
444
445        else if (pd->type == &typeid(float))
446          PyDict_SIS_Steal(packed, pd->name, PyFloat_FromDouble(me->getProperty_float(pd)));
447
448        else if (pd->type == &typeid(string)) {
449          string value;
450          me->getProperty_string(pd, value);
451          PyDict_SIS_Steal(packed, pd->name, PyString_FromString(value.c_str()));
452        }
453
454        else if (pd->type == &typeid(TValue)) {
455          TValue value;
456          me->getProperty_TValue(pd, value);
457          PyDict_SIS_Steal(packed, pd->name, Value_FromValue(value));
458        }
459
460        else if (pd->type == &typeid(TExample)) {
461          POrange mlobj;
462          me->getProperty_POrange(pd, mlobj);
463          if (mlobj)
464            PyDict_SIS_Steal(packed, pd->name, Example_FromWrappedExample(PExample(mlobj)));
465          else
466            PyDict_SetItemString(packed, pd->name, Py_None);
467        }
468   
469        else {
470          POrange mlobj;
471          me->getProperty_POrange(pd, mlobj);
472          PyDict_SIS_Steal(packed, pd->name, (PyObject *)WrapOrange(mlobj));
473        }
474      }
475    }
476
477    return packed;
478  PyCATCH
479}
480
481
482int Orange_setattr(TPyOrange *self, PyObject *pyname, PyObject *args);
483
484int unpackOrangeDictionary(PyObject *self, PyObject *dict)
485{
486  PyObject *d_key, *d_value;
487  Py_ssize_t i = 0;
488  while (PyDict_Next(dict, &i, &d_key, &d_value)) {
489//    if (Orange_setattr1((TPyOrange *)self, d_key, d_value) == -1)
490      if (Orange_setattrLow((TPyOrange *)self, d_key, d_value, false) == -1)
491        return -1;
492    }
493  return 0;
494}
495
496ORANGE_API PyObject *Orange__reduce__(PyObject *self, PyObject *, PyObject *)
497{
498    if (!((TOrangeType *)(self->ob_type))->ot_constructorAllowsEmptyArgs) {
499      PyErr_Format(PyExc_TypeError, "instances of type '%s' cannot be pickled", self->ob_type->tp_name);
500      return NULL;
501    }
502
503    return Py_BuildValue("O()N", self->ob_type, packOrangeDictionary(self));
504}
505
506
507
508PyObject *objectOnTheFly(PyObject *args, PyTypeObject *objectType)
509{
510  PyObject *emptyDict = PyDict_New();
511  PyObject *targs;
512  if (PyTuple_Check(args)) {
513    targs = args;
514    Py_INCREF(targs);
515  }
516  else
517    targs = Py_BuildValue("(O)", args);
518
519  PyObject *obj = NULL;
520  try {
521    obj = objectType->tp_new(objectType, targs, emptyDict);
522  }
523  catch (...) {
524    // do nothing; if it failed, the user probably didn't mean it
525  }
526
527  // If this failed, maybe the constructor actually expected a tuple...
528  if (!obj && PyTuple_Check(args)) {
529     PyErr_Clear();
530     Py_DECREF(targs);
531     targs = Py_BuildValue("(O)", args);
532     try {
533       obj = objectType->tp_new(objectType, targs, emptyDict);
534     }
535     catch (...) 
536     {}
537  }
538
539  if (obj) {
540    if (   objectType->tp_init != NULL
541        && objectType->tp_init(obj, targs, emptyDict) < 0) {
542          Py_DECREF(obj);
543          obj = NULL;
544    }
545  }
546
547  Py_DECREF(emptyDict);
548  Py_DECREF(targs);
549
550  return obj;
551}
552
553
554int Orange_setattr1(TPyOrange *self, char *name, PyObject *args)
555{
556  TOrange *me = (TOrange *)self->ptr;
557
558  const TPropertyDescription *propertyDescription = me->propertyDescription(name, true);
559  if (!propertyDescription)
560    return 1;
561
562  PyTRY
563    if (propertyDescription->readOnly) {
564      /* Property might be marked as readOnly, but have a specialized set function.
565         The following code is pasted from PyObject_GenericSetAttr.
566         If I'd call it here and the attribute is really read-only, PyObject_GenericSetAttr
567         would blatantly store it in the dictionary. */
568      PyObject *pyname = PyString_FromString(name);
569      PyObject *descr = _PyType_Lookup(self->ob_type, pyname);
570        PyObject *f = PYNULL;
571        if (descr != NULL && PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) {
572            descrsetfunc f = descr->ob_type->tp_descr_set;
573            if (f != NULL && PyDescr_IsData(descr))
574                return f(descr, (PyObject *)self, args);
575      }
576
577      PyErr_Format(PyExc_TypeError, "%s.%s: read-only attribute", self->ob_type->tp_name, name);
578      return -1;
579    }
580 
581    try {
582      const type_info &propertyType = *propertyDescription->type;
583
584      if ((propertyType==typeid(bool)) || (propertyType==typeid(int))) {
585        int value;
586        if (!PyArg_Parse(args, "i", &value)) {
587          PyErr_Format(PyExc_TypeError, "invalid parameter type for %s.%s', (int expected)", self->ob_type->tp_name, name);
588          return -1;
589        }
590        if (propertyType==typeid(bool))
591          me->setProperty(name, value!=0);
592        else
593          me->setProperty(name, value);
594        return 0;
595      }
596
597      if (propertyType==typeid(float)) {
598        float value;
599        if (!PyArg_Parse(args, "f", &value)) {
600          PyErr_Format(PyExc_TypeError, "invalid parameter type for %s.%s', (float expected)", self->ob_type->tp_name, name);
601          return -1;
602        }
603        me->setProperty(name, value);
604        return 0;
605      }
606
607      if (propertyType==typeid(string)) {
608        char *value;
609        if (!PyArg_Parse(args, "s", &value)) {
610          PyErr_Format(PyExc_TypeError, "invalid parameter type for %s.%s', (string expected)", self->ob_type->tp_name, name);
611          return -1;
612        }
613        me->setProperty(name, string(value));
614        return 0;
615      }
616
617      if (propertyType==typeid(TValue)) {
618        TValue value;
619        if (!convertFromPython(args, value))
620          return -1;
621        me->setProperty(name, value);
622        return 0;
623      }
624
625      if (propertyType==typeid(TExample)) {
626        if (args==Py_None) {
627          me->wr_setProperty(name, POrange());
628          return 0;
629        }
630        else {
631          if (!PyOrExample_Check(args)) {
632            PyErr_Format(PyExc_TypeError, "invalid parameter type for '%s.%s', (expected 'Example', got '%s')", self->ob_type->tp_name, name, args->ob_type->tp_name);
633            return -1;
634          }
635          me->wr_setProperty(name, POrange(PyExample_AS_Example(args)));
636          return 0;
637        }
638      }
639
640      if (1/*propertyType==typeid(POrange)*/) {
641        const type_info *wrappedType = propertyDescription->classDescription->type;
642
643        PyTypeObject *propertyPyType=(PyTypeObject *)FindOrangeType(*wrappedType);
644        if (!propertyPyType) {
645          PyErr_Format(PyExc_SystemError, "Orange class %s, needed for '%s.%s' not exported to Python", TYPENAME(*wrappedType), self->ob_type->tp_name, name);
646          return -1;
647        }
648
649        if (args==Py_None) {
650          me->wr_setProperty(name, POrange());
651          return 0;
652        }
653
654        // User might have supplied the correct object
655        if (PyObject_TypeCheck(args, propertyPyType)) {
656          me->wr_setProperty(name, PyOrange_AS_Orange((TPyOrange *)args));
657          return 0;
658        }
659
660        // User might have supplied parameters from which we can construct the object
661        if (propertyPyType->tp_new) {
662          PyObject *obj = objectOnTheFly(args, propertyPyType);
663          if (obj) {
664            bool success = true;
665            try {
666              me->wr_setProperty(name, PyOrange_AS_Orange((TPyOrange *)obj));
667            }
668            catch (...) {
669              success = false;
670            }
671            Py_DECREF(obj);
672            if (success)
673              return 0;
674          }
675        }
676
677        PyErr_Format(PyExc_TypeError, "invalid parameter type for '%s.%s', (expected '%s', got '%s')", self->ob_type->tp_name, name, propertyPyType->tp_name, args->ob_type->tp_name);
678        return -1;
679      }
680
681      PyErr_Format(PyExc_TypeError, "internal Orange error: unrecognized type '%s.%s'", self->ob_type->tp_name, name);
682      return -1;
683    } catch (exception err)
684    {
685      PyErr_Format(PyExc_TypeError, "error setting '%s.%s'", self->ob_type->tp_name, name);
686      return -1;
687    }
688  PyCATCH_1
689}
690
691
692int Orange_setattr1(TPyOrange *self, PyObject *pyname, PyObject *args)
693// This is a complete setattr, but without translation of obsolete names.
694{ 
695  if (!self)
696    PYERROR(PyExc_SystemError, "NULL Orange object", -1);
697
698  /* We first have to check for a specific handler.
699     The following code is pasted from PyObject_GenericSetAttr, but we can't
700     call it since it would store *all* attributes in the dictionary. */
701  PyObject *descr = _PyType_Lookup(self->ob_type, pyname);
702  PyObject *f = PYNULL;
703  if (descr != NULL && PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) {
704    descrsetfunc f = descr->ob_type->tp_descr_set;
705    if (f != NULL && PyDescr_IsData(descr))
706      return f(descr, (PyObject *)self, args);
707  }
708 
709  char *name=PyString_AsString(pyname);
710  int res = Orange_setattr1(self, name, args);
711  if (res != 1)
712    return res;
713
714  return 1; // attribute not set (not even attempted to), try something else
715}
716
717
718PyObject *Orange_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(ROOT, "()")
719{ return WrapNewOrange(mlnew TOrange(), type); }
720
721int Orange_init(PyObject *self, PyObject *, PyObject *keywords)
722{ PyTRY
723    return ((TPyOrange *)self)->call_constructed || SetAttr_FromDict(self, keywords, true) ? 0 : -1;
724  PyCATCH_1
725}
726
727
728void Orange_dealloc(TPyOrange *self)
729{
730  if (!self->is_reference) {
731    PyObject_GC_UnTrack((PyObject *)self);
732    mldelete self->ptr;
733  }
734
735  // This may cause troubles in multithread use
736  if (self->orange_dict) {
737    ((TPyOrange_DictProxy *)self->orange_dict)->backlink = NULL;
738    Py_DECREF(self->orange_dict);
739  }
740
741  self->ob_type->tp_free((PyObject *)self);
742}
743
744
745
746PyObject *Orange_getattr(TPyOrange *self, PyObject *name)
747// This calls getattr1; first with the given, than with the translated name
748{ 
749  PyTRY
750    PyObject *res = Orange_getattr1(self, name);
751    char *underscored = NULL;
752    if (!res) {
753        char *camel = PyString_AsString(name);
754        underscored = camel2underscore(camel);
755        if (underscored) {
756            PyObject *translation = PyString_FromString(underscored);
757            PyErr_Clear();
758            res = Orange_getattr1(self, translation);
759            Py_DECREF(translation);
760        }
761    }
762    if (!res) {
763        PyObject *translation = PyOrange_translateObsolete((PyObject *)self, name);
764        if (translation) {
765            PyErr_Clear();
766            res = Orange_getattr1(self, translation);
767            Py_DECREF(translation);
768        }
769    }
770
771    if (!res && underscored) {
772        PyMethodDef *mi = self->ob_type->tp_methods;
773        if (mi) {
774            for(; mi->ml_name; mi++) {
775                if (!strcmp(underscored, mi->ml_name)) {
776                    res = PyMethod_New((PyObject *)mi->ml_meth, (PyObject *)self, (PyObject *)(self->ob_type));
777                    break;
778                }
779            }
780        }
781    }
782
783    if (underscored) {
784        free(underscored);
785    }
786    return res;
787  PyCATCH
788}
789
790
791int Orange_setattrDictionary(TPyOrange *self, const char *name, PyObject *args, bool warn)
792{
793  PyObject *pyname = PyString_FromString(name);
794  int res = Orange_setattrDictionary(self, pyname, args, warn);
795  Py_DECREF(pyname);
796  return res;
797}
798
799int Orange_setattrDictionary(TPyOrange *self, PyObject* pyname, PyObject *args, bool warn)
800{ PyTRY
801    char *name = PyString_AsString(pyname);
802    if (args) {
803      /* Issue a warning unless name the name is in 'recognized_list' in some of the ancestors
804         or the instance's class only derived from some Orange's class, but is written in Python */
805      if (warn && PyOrange_CheckType(self->ob_type)) {
806        char **recognized = NULL;
807        for(PyTypeObject *otype = self->ob_type; otype && (!recognized || !*recognized); otype = otype->tp_base) {
808          recognized = PyOrange_CheckType(otype) ? ((TOrangeType *)otype)->ot_recognizedattributes : NULL;
809          if (recognized)
810            for(; *recognized && strcmp(*recognized, name); recognized++);
811        }
812
813        if (!recognized || !*recognized) {
814          char sbuf[255];
815          sprintf(sbuf, "'%s' is not a builtin attribute of '%s'", name, self->ob_type->tp_name);
816          if (PyErr_Warn(PyExc_OrangeAttributeWarning, sbuf))
817            return -1;
818        }
819      }
820
821      if (!self->orange_dict)
822        self->orange_dict = PyOrange_DictProxy_New(self);
823
824      return PyDict_SetItem(self->orange_dict, pyname, args);
825    }
826    else {
827      if (self->orange_dict)
828        return PyDict_DelItem(self->orange_dict, pyname);
829      else {
830        PyErr_Format(PyExc_AttributeError, "instance of '%s' has no attribute '%s'", self->ob_type->tp_name, name);
831        return -1;
832      }
833    }
834  PyCATCH_1
835}
836
837int Orange_setattrLow(TPyOrange *self, PyObject *pyname, PyObject *args, bool warn)
838// This calls setattr1; first with the given, than with the translated name
839{ PyTRY
840    if (!PyString_Check(pyname))
841      PYERROR(PyExc_AttributeError, "object's attribute name must be string", -1);
842
843    // Try to set it as C++ class member
844    int res = Orange_setattr1(self, pyname, args);
845    if (res!=1)
846      return res;
847   
848    PyErr_Clear();
849    char *camel = PyString_AsString(pyname);
850    char *underscored = camel2underscore(camel);
851    if (underscored) {
852        PyObject *translation = PyString_FromString(underscored);
853        free(underscored);
854        res = Orange_setattr1(self, translation, args);
855        Py_DECREF(translation);
856    }
857    if (res!=1)
858      return res;
859
860    PyErr_Clear();
861    // Try to translate it as an obsolete alias for C++ class member
862    PyObject *translation = PyOrange_translateObsolete((PyObject *)self, pyname);
863    if (translation) {   
864      char sbuf[255];
865      char *name = PyString_AsString(pyname);
866      char *transname = PyString_AsString(translation);
867      sprintf(sbuf, "'%s' is an (obsolete) alias for '%s'", name, transname);
868      if (PyErr_Warn(PyExc_DeprecationWarning, sbuf))
869        return -1;
870       
871      res = Orange_setattr1(self, translation, args);
872      Py_DECREF(translation);
873      return res;
874    }
875   
876    // Use instance's dictionary
877    return Orange_setattrDictionary(self, pyname, args, warn);
878   
879  PyCATCH_1
880}
881
882
883int Orange_setattr(TPyOrange *self, PyObject *pyname, PyObject *args)
884{ return Orange_setattrLow(self, pyname, args, true); }
885
886
887PyObject *callbackOutput(PyObject *self, PyObject *args, PyObject *kwds,
888                         char *formatname1, char *formatname2, PyTypeObject *toBase)
889{ 
890  PyObject *output;
891
892  char os1[256] = "__output_";
893  strcat(os1, formatname1);
894
895  char os2[256] = "__output_";
896  if (formatname2)
897    strcat(os2, formatname2);
898
899  for(PyTypeObject *type = self->ob_type;;type = type->tp_base) {
900    PyObject *type_py = (PyObject *)type;
901
902    if (PyObject_HasAttrString(type_py, os1)) {
903      output = PyObject_GetAttrString(type_py, os1);
904      break;
905    }
906
907    char os2[256] = "__output_";
908    if (formatname2 && PyObject_HasAttrString(type_py, os2)) {
909      output = PyObject_GetAttrString(type_py, os2);
910      break;
911    }
912
913    if (type==toBase)
914      return PYNULL;
915  }
916
917  PyObject *function = PyMethod_Function(output);
918  PyObject *result;
919  if (!args)
920    result = PyObject_CallFunction(function, "O", self);
921  else {
922    PyObject *margs = PyTuple_New(1+PyTuple_Size(args));
923   
924    Py_INCREF(self);
925    PyTuple_SetItem(margs, 0, self);
926    for(Py_ssize_t i = 0, e = PyTuple_Size(args); i<e; i++) {
927      PyObject *t = PyTuple_GetItem(args, i);
928      Py_INCREF(t);
929      PyTuple_SetItem(margs, i+1, t);
930    }
931
932    result = PyObject_Call(function, margs, kwds);
933    Py_DECREF(margs);
934  }
935
936  Py_DECREF(output);
937  return result;
938}
939 
940
941char const *getName(TPyOrange *self)
942{ static char *namebuf = NULL;
943
944  if (namebuf) {
945    delete namebuf;
946    namebuf = NULL;
947  }
948   
949  PyObject *pystr = PyString_FromString("name");
950  PyObject *pyname = Orange_getattr(self, pystr);
951  if (!pyname) {
952    PyErr_Clear();
953    return NULL;
954  }
955
956  Py_DECREF(pystr);
957
958  if (!PyString_Check(pyname)) {
959    pystr = PyObject_Repr(pyname);
960    Py_DECREF(pyname);
961    pyname = pystr;
962  }
963
964  const Py_ssize_t sze = PyString_Size(pyname);
965  if (sze) {
966    namebuf = mlnew char[sze+1];
967    strcpy(namebuf, PyString_AsString(pyname));
968  }
969  Py_DECREF(pyname);
970
971  return namebuf;
972}
973
974
975PyObject *Orange_repr(TPyOrange *self)
976{ PyTRY
977    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "repr", "str");
978    if (result)
979      return result;
980
981    const char *tp_name = self->ob_type->tp_name + (strncmp(self->ob_type->tp_name, "orange.", 7) ? 0 : 7);
982    const char *name = getName(self);
983    return name ? PyString_FromFormat("%s '%s'", tp_name, name)
984                : PyString_FromFormat("<%s instance at %p>", tp_name, self->ptr);
985  PyCATCH
986}
987
988
989PyObject *Orange_str(TPyOrange *self)
990{ PyTRY
991    PyObject *result = callbackOutput((PyObject *)self, NULL, NULL, "str", "repr");
992    if (result)
993      return result;
994
995    const char *tp_name = self->ob_type->tp_name + (strncmp(self->ob_type->tp_name, "orange.", 7) ? 0 : 7);
996    const char *name = getName(self);
997    return name ? PyString_FromFormat("%s '%s'", tp_name, name)
998                : PyString_FromFormat("<%s instance at %p>", tp_name, self->ptr);
999  PyCATCH
1000}
1001
1002
1003char const *genericNames[] = {"Classifier", "Learner", "Discretizer", NULL};
1004
1005PyObject *Orange_get_name(TPyOrange *self)
1006{
1007  PyTRY
1008    PyObject *pyname = Orange_getattr1(self, "name");
1009    if (!pyname) { 
1010      PyErr_Clear();
1011      if (self->orange_dict) {
1012        pyname = PyDict_GetItemString(self->orange_dict, "name");
1013        Py_XINCREF(pyname);
1014      }
1015    }
1016    if (pyname) {
1017      if (PyString_Check(pyname)) {
1018        return pyname;
1019      }
1020      PyObject *pystr = PyObject_Repr(pyname);
1021      Py_DECREF(pyname);
1022      return pystr;
1023    }
1024
1025    char const *tp_name = self->ob_type->tp_name;
1026    char const *dotp = tp_name + strlen(tp_name);
1027    while((dotp != tp_name) && (*dotp != '.')) {
1028      dotp--;
1029    }
1030    if (*dotp == '.') {
1031      dotp++;
1032    }
1033    if (*dotp == '_') {
1034      dotp++;
1035    }
1036    char *name = (char *)malloc(strlen(dotp) + 1);
1037    strcpy(name, dotp);
1038
1039    const int lenname = strlen(name);
1040    char *nameend = name + lenname;
1041    for(char const *const *gen = genericNames; *gen; gen++) {
1042        if (strlen(*gen) < lenname) {
1043            char *cap = nameend - strlen(*gen);
1044            if (!strcmp(cap, *gen)) {
1045              *cap = 0;
1046              break;
1047            }
1048        }
1049    }
1050    if ((*name >= 'A') && (*name <= 'Z')) {
1051      *name ^= 32;
1052      }
1053
1054    PyObject * orangename = PyString_FromString(name);
1055    free(name);
1056
1057    return orangename;
1058
1059  PyCATCH
1060}
1061
1062
1063
1064int Orange_set_name(TPyOrange *self, PyObject *arg)
1065{
1066  PyTRY
1067    int res = Orange_setattr1(self, "name", arg);
1068    if (res == 1) {
1069        res = Orange_setattrDictionary(self, "name", arg, false);
1070    }
1071    return res;
1072  PyCATCH_1
1073}
1074
1075
1076int Orange_nonzero(PyObject *self)
1077{ PyTRY
1078    if (self->ob_type->tp_as_sequence && self->ob_type->tp_as_sequence->sq_length)
1079      return self->ob_type->tp_as_sequence->sq_length(self) ? 1 : 0;
1080     
1081    if (self->ob_type->tp_as_mapping && self->ob_type->tp_as_mapping->mp_length)
1082      return self->ob_type->tp_as_mapping->mp_length(self) ? 1 : 0;
1083     
1084    return PyOrange_AS_Orange(self) ? 1 : 0;
1085  PyCATCH_1
1086}
1087
1088 
1089int Orange_hash(TPyOrange *self)
1090{ return _Py_HashPointer(self); }
1091
1092
1093PyObject *Orange_setattr_force(TPyOrange *self, PyObject *args) PYARGS(METH_VARARGS, "(name, value) -> None") //>setattr
1094{ 
1095  PyObject *pyname, *pyvalue;
1096  if (!PyArg_ParseTuple(args, "OO:Orange.setattr", &pyname, &pyvalue))
1097    return PYNULL;
1098  if (!PyString_Check(pyname))
1099    PYERROR(PyExc_TypeError, "attribute name must be a string", PYNULL);
1100  if (Orange_setattrLow(self, pyname, pyvalue, false) == -1)
1101    return PYNULL;
1102  RETURN_NONE;
1103}
1104
1105
1106PyObject *Orange_clone(TPyOrange *self) PYARGS(METH_NOARGS, "() -> a sensibly deep copy of the object")
1107{
1108  return WrapOrange(POrange(CLONE(TOrange, ((TOrange *)self->ptr))));
1109}
1110
1111PyObject *Orange_reference(TPyOrange *self) PYARGS(METH_NOARGS, "() -> reference; Returns unique id for an object")
1112{ PyTRY
1113    return PyInt_FromLong(long(self->ptr));
1114  PyCATCH
1115}
1116
1117
1118PyObject *Orange_typeid(TPyOrange *self) PYARGS(METH_NOARGS, "() -> int; Returns unique id for object's type")
1119{ PyTRY
1120    return PyInt_FromLong(long(&typeid(*self->ptr))); 
1121  PyCATCH
1122}
1123
1124
1125PyObject *Orange_dump(PyObject *self, PyObject *args, PyObject *kwd) PYARGS(METH_VARARGS | METH_KEYWORDS, "(formatname, ...) -> string; Prints the object into string")
1126{ PyTRY
1127    if (!args || !PyTuple_Size(args)) {
1128      PyErr_Format(PyExc_AttributeError, "missing arguments for '%s'.output", self->ob_type->tp_name);
1129      return PYNULL;
1130    }
1131
1132    PyObject *stype = PyTuple_GetItem(args, 0);
1133    if (!PyString_Check(stype)) {
1134      PyErr_Format(PyExc_AttributeError, "invalid format argument for '%s'.output", self->ob_type->tp_name);
1135      return PYNULL;
1136    }
1137    char *formatname = PyString_AsString(stype);
1138   
1139    PyObject *margs = PyTuple_New(PyTuple_Size(args)-1);
1140    for (Py_ssize_t i = 1, e = PyTuple_Size(args); i<e; i++) {
1141      PyObject *t = PyTuple_GetItem(args, i);
1142      Py_INCREF(t);
1143      PyTuple_SetItem(margs, i-1, t);
1144    }
1145
1146    PyObject *result = callbackOutput(self, margs, kwd, formatname);
1147    if (!result && !PyErr_Occurred())
1148      PyErr_Format(PyExc_AttributeError, "Class '%s' cannot be dumped as '%s'", self->ob_type->tp_name, formatname);
1149   
1150    Py_DECREF(margs);
1151    return result;
1152  PyCATCH
1153}
1154
1155
1156PyObject *Orange_write(PyObject *self, PyObject *args, PyObject *kwd) PYARGS(METH_VARARGS | METH_KEYWORDS, "(formatname, file, ...) -> string; Writes the object to a file")
1157{ PyTRY
1158    if (!args || PyTuple_Size(args)<2) {
1159      PyErr_Format(PyExc_AttributeError, "missing arguments for '%s'.output", self->ob_type->tp_name);
1160      return PYNULL;
1161    }
1162
1163    PyObject *stype = PyTuple_GetItem(args, 0);
1164    if (!PyString_Check(stype)) {
1165      PyErr_Format(PyExc_AttributeError, "invalid format argument for '%s'.output", self->ob_type->tp_name);
1166      return PYNULL;
1167    }
1168    char *formatname = PyString_AsString(stype);
1169   
1170    PyObject *margs = PyTuple_New(PyTuple_Size(args)-2);
1171    for (Py_ssize_t i = 2, e = PyTuple_Size(args); i<e; i++) {
1172      PyObject *t = PyTuple_GetItem(args, i);
1173      Py_INCREF(t);
1174      PyTuple_SetItem(margs, i-2, t);
1175    }
1176
1177    PyObject *result = callbackOutput(self, margs, kwd, formatname);
1178    Py_DECREF(margs);
1179
1180    if (!result)
1181      return PYNULL;
1182
1183    PyObject *pfile = PyTuple_GetItem(args, 1);
1184    if (pfile)
1185      if (PyFile_Check(pfile))
1186        Py_INCREF(pfile);
1187      else
1188        if (PyString_Check(pfile))
1189          pfile = PyFile_FromString(PyString_AsString(pfile), "wb");
1190        else
1191          pfile = NULL;
1192   
1193    if (!pfile) {
1194      PyErr_Format(PyExc_AttributeError, "invalid format argument for '%s'.output", self->ob_type->tp_name);
1195      Py_DECREF(result);
1196      return PYNULL;
1197    }
1198
1199    int succ = PyFile_WriteObject(result, pfile, Py_PRINT_RAW);
1200    Py_DECREF(result);
1201    Py_DECREF(pfile);
1202
1203    if (succ<0) {
1204      if (!PyErr_Occurred())
1205        PyErr_Format(PyExc_AttributeError, "Class '%s' cannot be written as '%s'", self->ob_type->tp_name, formatname);
1206      return PYNULL;
1207    }
1208    else
1209      RETURN_NONE;
1210
1211  PyCATCH
1212}
1213
1214
1215#include <typeinfo>
1216#include <string>
1217
1218
1219bool convertFromPythonWithML(PyObject *obj, string &str, const TOrangeType &base)
1220{ if (PyString_Check(obj))
1221    str=PyString_AsString(obj);
1222  else if (PyObject_TypeCheck(obj, (PyTypeObject *)const_cast<TOrangeType *>(&base)))
1223    str = string(getName((TPyOrange *)obj));
1224  else
1225    PYERROR(PyExc_TypeError, "invalid argument type", false);
1226
1227  return true;
1228}
1229
1230
1231#include "cls_orange.px"
Note: See TracBrowser for help on using the repository browser.