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. // Returns true on success, false on failure.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCClass:: bool DCClass::
pack_required_field(DCPacker &packer, PyObject *distobj, DCField *field) const { pack_required_field(DCPacker &packer, PyObject *distobj,
DCAtomicField *atom = field->as_atomic_field(); 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) { if (atom == (DCAtomicField *)NULL) {
ostringstream strm; ostringstream strm;
strm << "Cannot pack non-atomic field " << field->get_name() 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(empty_args);
Py_DECREF(func); Py_DECREF(func);
if (result == (PyObject *)NULL) { 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"; cerr << "Error when calling " << get_name << "\n";
return false; return false;
} }

View File

@ -69,7 +69,7 @@ PUBLISHED:
void direct_update(PyObject *distobj, const string &field_name, void direct_update(PyObject *distobj, const string &field_name,
const Datagram &datagram); const Datagram &datagram);
bool pack_required_field(DCPacker &packer, PyObject *distobj, bool pack_required_field(DCPacker &packer, PyObject *distobj,
DCField *field) const; const DCField *field) const;
Datagram client_format_update(const string &field_name, 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.had_error(), false);
nassertr(packer.get_current_field() == this, false); nassertr(packer.get_current_field() == this, false);
nassertr(PySequence_Check(sequence), false);
packer.pack_object(sequence); packer.pack_object(sequence);
if (!packer.had_error()) { if (!packer.had_error()) {
/* /*
@ -208,6 +206,7 @@ pack_args(DCPacker &packer, PyObject *sequence) const {
return true; return true;
} }
if (!Notify::ptr()->has_assert_failed()) {
PyObject *tuple = PySequence_Tuple(sequence); PyObject *tuple = PySequence_Tuple(sequence);
PyObject *str = PyObject_Str(tuple); PyObject *str = PyObject_Str(tuple);
@ -224,6 +223,7 @@ pack_args(DCPacker &packer, PyObject *sequence) const {
Py_DECREF(tuple); Py_DECREF(tuple);
nassert_raise(strm.str()); nassert_raise(strm.str());
}
return false; return false;
} }
#endif // HAVE_PYTHON #endif // HAVE_PYTHON

View File

@ -634,8 +634,6 @@ unpack_skip() {
void DCPacker:: void DCPacker::
pack_object(PyObject *object) { pack_object(PyObject *object) {
nassertv(_mode == M_pack || _mode == M_repack); nassertv(_mode == M_pack || _mode == M_repack);
PyObject *str = PyObject_Str(object);
Py_DECREF(str);
if (PyInt_Check(object)) { if (PyInt_Check(object)) {
pack_int(PyInt_AS_LONG(object)); pack_int(PyInt_AS_LONG(object));
@ -654,7 +652,44 @@ pack_object(PyObject *object) {
pack_string(string(buffer, length)); pack_string(string(buffer, length));
} }
} else if (PySequence_Check(object)) { } 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(); push();
int size = PySequence_Size(object); int size = PySequence_Size(object);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@ -663,6 +698,19 @@ pack_object(PyObject *object) {
Py_DECREF(element); Py_DECREF(element);
} }
pop(); 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;
}
} }
} }
#endif // HAVE_PYTHON #endif // HAVE_PYTHON
@ -1034,6 +1082,33 @@ clear() {
_root = NULL; _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 #ifdef HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCPacker::unpack_class_object // Function: DCPacker::unpack_class_object

View File

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