read parameters from concrete classes

This commit is contained in:
David Rose 2004-06-28 22:58:15 +00:00
parent 65e677ad21
commit 19e98401f1
5 changed files with 134 additions and 30 deletions

View File

@ -423,8 +423,34 @@ direct_update(PyObject *distobj, const string &field_name,
// Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool DCClass::
pack_required_field(DCPacker &packer, PyObject *distobj, DCField *field) const {
DCAtomicField *atom = field->as_atomic_field();
pack_required_field(DCPacker &packer, PyObject *distobj,
const DCField *field) const {
const DCParameter *parameter = ((DCField *)field)->as_parameter();
if (parameter != (DCParameter *)NULL) {
// This is the easy case: to pack a parameter, we just look on the
// class object for the data element.
string field_name = field->get_name();
if (!PyObject_HasAttrString(distobj, (char *)field_name.c_str())) {
ostringstream strm;
strm << "Data element " << field_name
<< ", required by dc file for dclass " << get_name()
<< ", not defined on object.";
nassert_raise(strm.str());
return false;
}
PyObject *result =
PyObject_GetAttrString(distobj, (char *)field_name.c_str());
nassertr(result != (PyObject *)NULL, false);
// Now pack the value into the datagram.
bool pack_ok = parameter->pack_args(packer, result);
Py_DECREF(result);
return pack_ok;
}
const DCAtomicField *atom = ((DCField *)field)->as_atomic_field();
if (atom == (DCAtomicField *)NULL) {
ostringstream strm;
strm << "Cannot pack non-atomic field " << field->get_name()
@ -476,6 +502,8 @@ pack_required_field(DCPacker &packer, PyObject *distobj, DCField *field) const {
Py_DECREF(empty_args);
Py_DECREF(func);
if (result == (PyObject *)NULL) {
// We don't set this as an exception, since presumably the Python
// method itself has already triggered a Python exception.
cerr << "Error when calling " << get_name << "\n";
return false;
}

View File

@ -69,7 +69,7 @@ PUBLISHED:
void direct_update(PyObject *distobj, const string &field_name,
const Datagram &datagram);
bool pack_required_field(DCPacker &packer, PyObject *distobj,
DCField *field) const;
const DCField *field) const;
Datagram client_format_update(const string &field_name,

View File

@ -195,8 +195,6 @@ pack_args(DCPacker &packer, PyObject *sequence) const {
nassertr(!packer.had_error(), false);
nassertr(packer.get_current_field() == this, false);
nassertr(PySequence_Check(sequence), false);
packer.pack_object(sequence);
if (!packer.had_error()) {
/*
@ -208,22 +206,24 @@ pack_args(DCPacker &packer, PyObject *sequence) const {
return true;
}
PyObject *tuple = PySequence_Tuple(sequence);
PyObject *str = PyObject_Str(tuple);
ostringstream strm;
if (packer.had_pack_error()) {
strm << "Incorrect arguments to field: " << get_name()
<< PyString_AsString(str);
} else {
strm << "Value out of range on field: " << get_name()
<< PyString_AsString(str);
}
Py_DECREF(str);
Py_DECREF(tuple);
if (!Notify::ptr()->has_assert_failed()) {
PyObject *tuple = PySequence_Tuple(sequence);
PyObject *str = PyObject_Str(tuple);
nassert_raise(strm.str());
ostringstream strm;
if (packer.had_pack_error()) {
strm << "Incorrect arguments to field: " << get_name()
<< PyString_AsString(str);
} else {
strm << "Value out of range on field: " << get_name()
<< PyString_AsString(str);
}
Py_DECREF(str);
Py_DECREF(tuple);
nassert_raise(strm.str());
}
return false;
}
#endif // HAVE_PYTHON

View File

@ -634,8 +634,6 @@ unpack_skip() {
void DCPacker::
pack_object(PyObject *object) {
nassertv(_mode == M_pack || _mode == M_repack);
PyObject *str = PyObject_Str(object);
Py_DECREF(str);
if (PyInt_Check(object)) {
pack_int(PyInt_AS_LONG(object));
@ -654,15 +652,65 @@ pack_object(PyObject *object) {
pack_string(string(buffer, length));
}
} else if (PySequence_Check(object)) {
push();
int size = PySequence_Size(object);
for (int i = 0; i < size; i++) {
PyObject *element = PySequence_GetItem(object, i);
pack_object(element);
Py_DECREF(element);
} else {
DCClass *dclass = NULL;
const DCClassParameter *class_param = ((DCPackerInterface *)get_current_field())->as_class_parameter();
if (class_param != (DCClassParameter *)NULL) {
dclass = class_param->get_class();
}
int size = PySequence_Size(object);
// If dclass is not NULL, the packer is expecting a class object.
// There are then two cases: (1) the user has supplied a matching
// class object, or (2) the user has supplied a sequence object.
// Unfortunately, it may be difficult to differentiate these two
// cases, since a class object may also be a sequence object.
// The rule to differentiate them is:
// (1) If the supplied class object is an instance of the expected
// class object, it is considered to be a class object.
// (2) Otherwise, if the supplied class object has a __len__()
// method (i.e. PySequence_Size() returns a number >= 0), then it
// is considered to be a sequence.
// (3) Otherwise, it is considered to be a class object.
if (dclass != (DCClass *)NULL &&
((dclass->get_class_def() != (PyObject *)NULL &&
PyObject_IsInstance(object, dclass->get_class_def())) ||
size < 0)) {
// The supplied object is either an instance of the expected
// class object, or the size is less than 0--this is case (1) or
// (3).
pack_class_object(dclass, object);
} else if (size >= 0) {
// The supplied object is not an instance of the expected class
// object, and it does return a valid size. This is case (2).
push();
int size = PySequence_Size(object);
for (int i = 0; i < size; i++) {
PyObject *element = PySequence_GetItem(object, i);
pack_object(element);
Py_DECREF(element);
}
pop();
} else {
// The supplied object does not return a valid size, and we
// weren't expecting a class parameter. This is none of the
// above, an error.
ostringstream strm;
PyObject *str = PyObject_Str(object);
strm << "Don't know how to pack object: "
<< PyString_AsString(str) << "\n";
Py_DECREF(str);
nassert_raise(strm.str());
_pack_error = true;
}
pop();
}
}
#endif // HAVE_PYTHON
@ -1034,6 +1082,33 @@ clear() {
_root = NULL;
}
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: DCPacker::pack_class_object
// Access: Private
// Description: Given that the current element is a ClassParameter
// for a Python class object, try to extract the
// appropriate values from the class object and pack in.
////////////////////////////////////////////////////////////////////
void DCPacker::
pack_class_object(DCClass *dclass, PyObject *object) {
PyObject *str = PyObject_Str(object);
cerr << "pack_class_object(" << dclass->get_name() << ", "
<< PyString_AsString(str) << ")\n";
Py_DECREF(str);
push();
while (more_nested_fields()) {
const DCField *field = ((DCPackerInterface *)get_current_field())->as_field();
nassertv(field != (DCField *)NULL);
if (!dclass->pack_required_field(*this, object, field)) {
break;
}
}
pop();
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: DCPacker::unpack_class_object

View File

@ -178,6 +178,7 @@ private:
void clear();
#ifdef HAVE_PYTHON
void pack_class_object(DCClass *dclass, PyObject *object);
PyObject *unpack_class_object(DCClass *dclass);
void set_class_element(PyObject *object, const DCField *field);
#endif