# HG changeset patch # User Mike Miller # Date 1472245537 25200 # Node ID 0e4097c6678877c22ff1611ec83fd7e9bcb75199 # Parent b20b8cf8ad07637bdd67110cbb87dc74c5b1471a Report a Python object's fully qualified class name correctly * oct-py-util.cc (pytave::py_object_class_name): Return the correct fully qualified class name, including module prefix. (pytave::is_py_kwargs_argument): Check for class name "__main__._OctaveKwargs". * __py_struct_from_dict__.cc (F__py_class_name__): New function. * @pyobject/methods.m (pyobject.methods): Use __py_class_name__. * @pyobject/pyobject.m (pyobject.class): Likewise. diff -r b20b8cf8ad07 -r 0e4097c66788 @pyobject/methods.m --- a/@pyobject/methods.m Fri Aug 26 13:59:18 2016 -0700 +++ b/@pyobject/methods.m Fri Aug 26 14:05:37 2016 -0700 @@ -79,10 +79,7 @@ modulename = char (pycall ("getattr", x, "__name__")); printf ("Methods for Python module '%s':\n", modulename); else - ## FIXME: should be `class (x)` - classref = pycall ("getattr", x, "__class__"); - classname = char (pycall ("getattr", classref, "__name__")); - printf ("Methods for Python class '%s':\n", classname); + printf ("Methods for Python class '%s':\n", __py_class_name__ (x)); endif disp (list_in_columns (mtds_list)); else diff -r b20b8cf8ad07 -r 0e4097c66788 @pyobject/pyobject.m --- a/@pyobject/pyobject.m Fri Aug 26 13:59:18 2016 -0700 +++ b/@pyobject/pyobject.m Fri Aug 26 14:05:37 2016 -0700 @@ -96,11 +96,8 @@ endfunction function s = class (x) - idx = struct ("type", ".", "subs", "__class__"); - class_ref = subsref (x, idx); - idx = struct ("type", ".", "subs", "__name__"); - s = subsref (class_ref, idx); - s = sprintf ("py.%s", char (s)); + s = __py_class_name__ (x); + s = sprintf ("py.%s", s); endfunction function y = double (x) diff -r b20b8cf8ad07 -r 0e4097c66788 __py_struct_from_dict__.cc --- a/__py_struct_from_dict__.cc Fri Aug 26 13:59:18 2016 -0700 +++ b/__py_struct_from_dict__.cc Fri Aug 26 14:05:37 2016 -0700 @@ -34,6 +34,41 @@ #include "oct-py-util.h" #include "octave_to_python.h" +DEFUN_DLD (__py_class_name__, args, , + "-*- texinfo -*-\n\ +@deftypefn {} {} __py_class_name__ (@var{obj})\n\ +Return the name of the class of the Python object @var{obj}.\n\ +\n\ +This is a private internal function not intended for direct use.\n\ +@end deftypefn") +{ + if (args.length () != 1) + print_usage (); + + if (! (args(0).is_object () && args(0).class_name () == "pyobject")) + error ("__py_class_name__: argument must be a valid Python object"); + + Py_Initialize (); + + PyObject *obj = pytave::pyobject_unwrap_object (args(0)); + std::string name = pytave::py_object_class_name (obj); + Py_DECREF (obj); + + return ovl (name); +} + +/* +%!assert (__py_class_name__ (pyeval ("None")), "NoneType") +%!assert (__py_class_name__ (pyeval ("0")), "int") +%!assert (__py_class_name__ (pyeval ("'Octave'")), "str") +%!assert (__py_class_name__ (pyeval ("[]")), "list") +%!assert (__py_class_name__ (pyeval ("__import__('array').array('d')")), "array.array") + +%!error __py_class_name__ () +%!error __py_class_name__ (1) +%!error __py_class_name__ (1, 2) +*/ + DEFUN_DLD (__py_int64_scalar_value__, args, nargout, "-*- texinfo -*-\n\ @deftypefn {} {} __py_int64_scalar_value__ (@var{x})\n\ diff -r b20b8cf8ad07 -r 0e4097c66788 oct-py-util.cc --- a/oct-py-util.cc Fri Aug 26 13:59:18 2016 -0700 +++ b/oct-py-util.cc Fri Aug 26 14:05:37 2016 -0700 @@ -126,9 +126,33 @@ std::string py_object_class_name (PyObject *obj) { - PyObject *class_ = obj ? PyObject_GetAttrString (obj, "__class__") : 0; - PyObject *name_ = class_ ? PyObject_GetAttrString (class_, "__name__") : 0; - return name_ ? extract_py_str (name_): ""; + std::string retval; + + PyObject *type = obj ? PyObject_GetAttrString (obj, "__class__") : 0; + if (type) + { + PyObject *mod = PyObject_GetAttrString (type, "__module__"); + + PyObject *name = 0; + if (PyObject_HasAttrString (type, "__qualname__")) + name = PyObject_GetAttrString (type, "__qualname__"); + else + name = PyObject_GetAttrString (type, "__name__"); + + std::string mod_str = mod ? extract_py_str (mod) : ""; + std::string name_str = name ? extract_py_str (name) : ""; + + Py_DECREF (type); + Py_XDECREF (mod); + Py_XDECREF (name); + + if (mod_str == py_builtins_module_name ()) + retval = name_str; + else + retval = mod_str + "." + name_str; + } + + return retval; } // FIXME: could make this into a class/singleton wrapper a la Octave core @@ -223,7 +247,7 @@ bool is_py_kwargs_argument (PyObject *obj) { - if (obj && py_object_class_name (obj) == "_OctaveKwargs" + if (obj && py_object_class_name (obj) == "__main__._OctaveKwargs" && PyObject_HasAttrString (obj, "is_kwargs_argument")) { PyObject *flag = PyObject_GetAttrString (obj, "is_kwargs_argument");