📄 cls_value.cpp
字号:
/*
This file is part of Orange.
Orange is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Orange is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Orange; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Authors: Janez Demsar, Blaz Zupan, 1996--2002
Contact: janez.demsar@fri.uni-lj.si
*/
#ifdef _MSC_VER
#pragma warning (disable : 4786 4114 4018 4267 4244)
#endif
#include "cls_value.hpp"
#include "cls_orange.hpp"
#include "vars.hpp"
#include "stringvars.hpp"
#include "pythonvars.hpp"
#include "values.hpp"
#include "vectortemplates.hpp"
#include "externs.px"
#define CHECK_VARIABLE \
if (!self->variable) PYERROR(PyExc_TypeError, "'variable' not set", PYNULL);
#define CHECK_SPECIAL_OTHER \
if (self->value.isSpecial()) \
PYERROR(PyExc_TypeError, "attribute value unknown", PYNULL); \
if ((self->value.varType!=TValue::INTVAR) && (self->value.varType!=TValue::FLOATVAR)) \
PYERROR(PyExc_TypeError, "attribute is not an ordinary discrete or continuous", PYNULL);
DATASTRUCTURE(Value, TPyValue, 0)
ABSTRACT(SomeValue, Orange)
/* Converts a value into an appropriate python variable.
Behaves as convertToPythonNative(const TValue &, PVariable)
when the variable is not given. */
PyObject *convertToPythonNative(const TValue &val)
{ return convertToPythonNative(val, PVariable()); }
/* Converts a value into an appropriate python variable.
Behaves as convertToPythonNative(const TValue &, PVariable);
variable can be there or not. */
PyObject *convertToPythonNative(const TPyValue *value)
{ return convertToPythonNative(value->value, value->variable); }
/* Converts a value into an appropriate python variable.
If value is known (e.g. not DC, DK...)
- continuous values are returned as ordinary python floats
- discrete are returned as strings (variable is required)
- string values are returned as strings
- other values are return as ordinary orange objects
If value is special
- if the variable is given, its val2str is used to get a string
- if the variable is not given, '?', '~' and '.' are returned
for DK, DC and other, respectively.
FAILS if the value is discrete and variable is not given
*/
PyObject *convertToPythonNative(const TValue &val, PVariable var)
{
if ((val.varType==TValue::FLOATVAR) && !val.isSpecial())
return PyFloat_FromDouble(double(val.floatV));
if (val.varType == PYTHONVAR) {
PyObject *res = val.svalV ? ((TPythonValue &)(val.svalV.getReference())).value : Py_None;
Py_INCREF(res);
return res;
}
if ((val.varType == STRINGVAR) && val.svalV) {
string s;
val.svalV.AS(TStringValue)->val2str(s);
return PyString_FromString(s.c_str());
}
if ((val.varType!=TValue::INTVAR) && val.svalV)
return WrapOrange((const_cast<TValue &>(val)).svalV);
if (var) { // && (val.varType == TValue::INTVAR || val.isSpecial)
string vs;
var->val2str(val, vs);
return PyString_FromString(vs.c_str());
}
if (val.isSpecial())
if (val.isDK())
return PyString_FromString("?");
else if (val.isDC())
return PyString_FromString("~");
else
return PyString_FromString(".");
PYERROR(PyExc_TypeError, "unknown value type", PYNULL);
}
/* The main routine for converting values from python to TValue.
If arguments are given as a
- Value, it is simply copied.
The variable is checked if given.
- SomeValue, it is copied as such.
If the variable is discrete or continuous, SomeValue must
be DiscDistribution or ContDistribution.
- string, we convert it to a value
The variable must be given unless the string is '?', '~'
(in this case INTVAR is ocnstructed)
We could return a StringValue here, but if user passes a
string without descriptor it is more probable that he just
forgot it. I doubt that many would construct StringValues.)
- int - if variable is given and is discrete, an integer value
is constructed. If the variable is derived from
EnumVariable the range is also tested
- if variable is given and is continuous, a continuous
value is constructed
- if variable is given and is of other type, an error is
raised
- if the variable is not given, an integer value is constructed
- float - a continuous value is constructed.
If the variable is given, it is checked that it is continuous
- other types: if it can be converted to float and the variable is
given and is continuous, a continuous value is constructed.
Otherwise, an exception is raised.
*/
bool convertFromPython(PyObject *args, TValue &value, PVariable var)
{
if (PyOrValue_Check(args)) {
if (var && PyValue_AS_Variable(args) && (PyValue_AS_Variable(args)!=var)) {
PyErr_Format(PyExc_TypeError, "wrong attribute value (expected value of '%s', got value of '%s')", var->name.c_str(), PyValue_AS_Variable(args)->name.c_str());
return false;
}
else
value = PyValue_AS_Value(args);
return true;
}
if (PyOrSomeValue_Check(args)) {
if (var) {
if ((var->varType==TValue::INTVAR) && !PyOrDiscDistribution_Check(args)) {
PyErr_Format(PyExc_TypeError, "attribute '%s' expects DiscDistribution, '%s' given", var->name.c_str(), args->ob_type->tp_name);
return false;
}
if ((var->varType==TValue::FLOATVAR) && !PyOrContDistribution_Check(args)) {
PyErr_Format(PyExc_TypeError, "attribute '%s' expects ContDistribution, '%s' given", var->name.c_str(), args->ob_type->tp_name);
return false;
}
}
int vtype;
if (PyOrDiscDistribution_Check(args))
vtype = TValue::INTVAR;
else if (PyOrContDistribution_Check(args))
vtype = TValue::FLOATVAR;
else if (PyOrStringValue_Check(args))
vtype = STRINGVAR;
else if (PyOrPythonValue_Check(args))
vtype = PYTHONVAR;
else
raiseError("unknovn variable type");
value = TValue(PyOrange_AsSomeValue(args), vtype);
return true;
}
if (PyString_Check(args)) {
char *str = PyString_AsString(args);
if (var)
var->str2val(str, value);
else
if (!strcmp(str, "?"))
value = TValue(TValue::INTVAR, valueDK);
else if (!strcmp(str, "~"))
value = TValue(TValue::INTVAR, valueDC);
else {
PyErr_Format(PyExc_TypeError, "cannot convert '%s' to a value of an unknown attribute", str);
return false;
}
return true;
}
if (var && var->varType == PYTHONVAR) {
Py_INCREF(args);
value = TValue(mlnew TPythonValue(args), PYTHONVAR);
return true;
}
if (PyInt_Check(args)) {
int ii = int(PyInt_AsLong(args));
if (var) {
if (var->varType == TValue::FLOATVAR) {
value = TValue(float(ii));
return true;
}
if (var->varType == TValue::INTVAR) {
if (var.is_derived_from(TEnumVariable)) {
int nv = var.AS(TEnumVariable)->noOfValues();
if (ii >= nv) {
PyErr_Format(PyExc_TypeError, "value index %i out of range (0 - %i)", ii, nv-1);
return false;
}
}
value = TValue(ii);
return true;
}
PyErr_Format(PyExc_TypeError, "cannot convert an integer to a value of attribute '%s'", var->name.c_str());
return false;
}
value = TValue(ii);
return true;
}
if (PyFloat_Check(args)) {
if (var && (var->varType != TValue::FLOATVAR)) {
PyErr_Format(PyExc_TypeError, "cannot convert a float to a value of attribute '%s'", var->name.c_str());
return false;
}
value = TValue(float(PyFloat_AsDouble(args)));
return true;
}
if (var && (var->varType == TValue::FLOATVAR)) {
PyObject *pyfloat = PyNumber_Float(args);
if (!pyfloat) {
PyErr_Format(PyExc_TypeError, "cannot convert an object of type '%s' to value of attribute '%s'", args->ob_type->tp_name, var->name.c_str());
return false;
}
value = TValue(float(PyFloat_AsDouble(pyfloat)));
Py_DECREF(pyfloat);
return true;
}
if (var)
PyErr_Format(PyExc_TypeError, "cannot convert an object of type '%s' to value of attribute '%s'", args->ob_type->tp_name, var->name.c_str());
else
PyErr_Format(PyExc_TypeError, "cannot convert an object of type '%s' to value of attribute", args->ob_type->tp_name);
return false;
}
/* Builds a TPyValue from arguments given in Python.
See Value_FromArguments for details. */
bool convertFromPython(PyObject *args, TPyValue *&value)
{
value = (TPyValue *)Value_FromArguments((PyTypeObject *)&PyOrValue_Type, args);
return value!=NULL;
}
/* The main constructor for TPyValue.
Gets a value and descriptor, allocates the memory and assigns fields. */
PyObject *Value_FromVariableValueType(PyTypeObject *type, PVariable var, const TValue &val)
{
TPyValue *value = PyObject_GC_New(TPyValue, type);
if (!value)
return PYNULL;
/* The below is needed since 'value' was allocated in C code, so it's
constructor has never been called and the below fields (wrapped pointers)
contain random data, which would lead to crash when trying to deallocate
them. */
value->value.svalV.init();
value->variable.init();
value->value = val;
value->variable = var;
PyObject_GC_Track(value);
return (PyObject *)value;
}
/* Constructs a value from arguments in Python. Arguments must be given as a tuple
with at least one element.
- If the single element is a variable, a DK() value for that attribute is returned
- Otherwise, it is converted using convertFromPython, without descriptor given
If there are two elements
- If one is variable, convertFromPython is used, passing the variable and the other
- Otherwise, both must be integers and are used for varType and valueType.
*/
PyObject *Value_FromArguments(PyTypeObject *type, PyObject *args)
{
PyTRY
PyObject *obj1;
PyObject *obj2 = NULL;
if (!PyArg_ParseTuple(args, "O|O:Value", &obj1, &obj2))
return PYNULL;
if (!obj2) {
if (PyOrVariable_Check(obj1))
return Value_FromVariableType(type, PyOrange_AsVariable(obj1));
else {
TValue val;
return convertFromPython(obj1, val) ? Value_FromValueType(type, val) : PYNULL;
}
}
TValue val;
if (PyOrVariable_Check(obj1)) {
const PVariable &var = PyOrange_AsVariable(obj1);
return convertFromPython(obj2, val, var) ? Value_FromVariableValueType(type, var, val) : PYNULL;
}
else if (PyOrVariable_Check(obj2)) {
const PVariable &var = PyOrange_AsVariable(obj2);
return convertFromPython(obj1, val, var) ? Value_FromVariableValueType(type, var, val) : PYNULL;
}
else if (PyInt_Check(obj1) && PyInt_Check(obj2)) {
int vartype = int(PyInt_AsLong(obj1));
if (vartype == STRINGVAR)
return Value_FromValueType(type, TValue(STRINGVAR, (signed char)PyInt_AsLong(obj2)));
if (vartype > TValue::FLOATVAR) {
PyErr_Format(PyExc_IndexError, "invalid value type (%i)", vartype);
return PYNULL;
}
return Value_FromValueType(type, TValue((char)vartype, (signed char)PyInt_AsLong(obj2)));
}
PYERROR(PyExc_TypeError, "Value(): invalid arguments", PYNULL);
PyCATCH
}
PyObject *Value_new(PyTypeObject *type, PyObject *args, PyObject *keywords) BASED_ON(ROOT, "([Variable], [int | float | Value | ...])")
{ return Value_FromArguments(type, args); }
void Value_dealloc(TPyValue *self)
{ self->variable = PVariable();
self->value.~TValue();
if (PyObject_IsPointer(self)) {
PyObject_GC_UnTrack((PyObject *)self);
self->ob_type->tp_free((PyObject *)self);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -