view oct-py-util.cc @ 372:b20b8cf8ad07

Make an internal function to return the name of the builtins module * oct-py-util.cc (pytave::py_builtins_module_name): New function. (pytave::py_builtins_module): Use it.
author Mike Miller <mtmiller@octave.org>
date Fri, 26 Aug 2016 13:59:18 -0700
parents 1470ed26917a
children 0e4097c66788
line wrap: on
line source

/*

Copyright (C) 2016 Mike Miller

This file is part of Pytave.

Pytave 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 3 of the License, or (at your
option) any later version.

Pytave 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 Pytave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#if defined (HAVE_CONFIG_H)
#  include <config.h>
#endif

#include <oct.h>
#include <octave/parse.h>

#include "oct-py-types.h"
#include "oct-py-util.h"

// FIXME: only here for boost::python::error_already_set
#include <boost/python.hpp>

namespace pytave
{

inline std::string
py_builtins_module_name ()
{
#if PY_VERSION_HEX >= 0x03000000
  return "builtins";
#else
  return "__builtin__";
#endif
}

PyObject *
py_builtins_module ()
{
  return py_import_module (py_builtins_module_name ());
}

PyObject *
py_find_function (PyObject *module, const std::string& name)
{
  if (module && PyModule_Check (module))
    {
      PyObject *obj = PyObject_GetAttrString (module, name.c_str ());
      if (obj && ! PyCallable_Check (obj))
        {
          Py_CLEAR (obj);
        }

      return obj;
    }

  return 0;
}

PyObject *
py_find_function (const std::string& module, const std::string& name)
{
  PyObject *mod = py_import_module (module);
  PyObject *func =  py_find_function (mod, name);
  Py_XDECREF (mod);
  return func;
}

PyObject *
py_find_function (const std::string& name)
{
  std::string::size_type idx = name.rfind (".");
  if (idx == std::string::npos)
    {
      PyObject *func = py_find_function ("__main__", name);
      if (! func)
        func = py_find_function (py_builtins_module (), name);
      return func;
    }
  else
    {
      std::string module = name.substr (0, idx);
      std::string function = name.substr (idx + 1);
      return py_find_function (module, function);
    }
}

PyObject *
py_find_type (const std::string& name)
{
  PyObject *obj = py_find_function (name);
  if (obj && PyType_Check (obj))
    return obj;

  Py_XDECREF (obj);
  return 0;
}

PyObject *
py_import_module (const std::string& name)
{
  return PyImport_ImportModule (name.c_str ());
}

bool
py_isinstance (PyObject *obj, PyObject *type)
{
  if (obj && type)
    return static_cast<bool> (PyObject_IsInstance (obj, type));

  return false;
}

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_): "";
}

// FIXME: could make this into a class/singleton wrapper a la Octave core
PyObject *objstore = 0;

inline PyObject *
py_objstore ()
{
  if (! objstore)
    {
      PyObject *main = py_import_module ("__main__");
      PyObject *ns = main ? PyObject_GetAttrString (main, "__dict__") : 0;
      PyObject *dict = ns ? PyDict_GetItemString (ns, "_in_octave") : 0;

      if (dict)
        Py_INCREF (dict);

      if (! dict)
        {
          dict = PyDict_New ();
          if (dict && ns)
            PyDict_SetItemString (ns, "_in_octave", dict);
        }

      if (! dict)
        throw boost::python::error_already_set ();

      objstore = dict;
    }
  return objstore;
}

void
py_objstore_del (uint64_t key)
{
  PyObject *store = py_objstore ();
  PyObject *key_obj = make_py_int (key);
  PyObject *key_fmt = PyNumber_ToBase (key_obj, 16);
  PyDict_DelItem (store, key_fmt);
  Py_DECREF (key_fmt);
  Py_DECREF (key_obj);
}

PyObject *
py_objstore_get (uint64_t key)
{
  PyObject *store = py_objstore ();
  PyObject *key_obj = make_py_int (key);
  PyObject *key_fmt = PyNumber_ToBase (key_obj, 16);
  PyObject *obj = PyDict_GetItem (store, key_fmt);
  Py_DECREF (key_fmt);
  Py_DECREF (key_obj);
  if (obj)
    Py_INCREF (obj);
  return obj;
}

uint64_t
py_objstore_put (PyObject *obj)
{
  PyObject *store = py_objstore ();
  uint64_t key = reinterpret_cast<uint64_t> (obj);
  PyObject *key_obj = make_py_int (key);
  PyObject *key_fmt = PyNumber_ToBase (key_obj, 16);
  PyDict_SetItem (store, key_fmt, obj);
  Py_DECREF (key_fmt);
  Py_DECREF (key_obj);
  return key;
}

octave_value
pyobject_wrap_object (PyObject *obj)
{
  uint64_t key = py_objstore_put (obj);
  octave_value_list out = feval ("pyobject", ovl (0, octave_uint64 (key)), 1);
  return out(0);
}

PyObject *
pyobject_unwrap_object (const octave_value& value)
{
  if (value.is_object () && value.class_name () == "pyobject")
    {
      octave_value_list out = feval ("id", ovl (value), 1);
      uint64_t key = out(0).uint64_scalar_value ();
      return py_objstore_get (key);
    }

  return 0;
}

bool
is_py_kwargs_argument (PyObject *obj)
{
  if (obj && py_object_class_name (obj) == "_OctaveKwargs"
      && PyObject_HasAttrString (obj, "is_kwargs_argument"))
    {
      PyObject *flag = PyObject_GetAttrString (obj, "is_kwargs_argument");
      if (flag && PyBool_Check (flag) && PyObject_IsTrue (flag))
        return true;
    }
  return false;
}

PyObject *
update_py_dict (PyObject *dict_orig, PyObject *dict_new)
{
  PyObject *dict = dict_orig ? dict_orig : PyDict_New ();
  PyDict_Update (dict, dict_new);
  return dict;
}

}