From a65017902e878f813c8e4ed3a40dd92b1940fa95 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 4 Feb 2016 23:02:07 +0100 Subject: [PATCH] set __module__ attribute of functions (fixes #95) --- example/example11.ref | 8 ++-- example/example2.py | 7 +++ example/example2.ref | 93 +++++++++++++++++++------------------ include/pybind11/attr.h | 14 +++++- include/pybind11/pybind11.h | 27 +++++++---- 5 files changed, 91 insertions(+), 58 deletions(-) diff --git a/example/example11.ref b/example/example11.ref index 7d75056f1..8edc06580 100644 --- a/example/example11.ref +++ b/example/example11.ref @@ -1,19 +1,19 @@ -Help on built-in function kw_func +Help on built-in function kw_func in module example kkww__ffuunncc(...) Signature : (x : int, y : int) -> NoneType -Help on built-in function kw_func2 +Help on built-in function kw_func2 in module example kkww__ffuunncc22(...) Signature : (x : int = 100L, y : int = 200L) -> NoneType -Help on built-in function kw_func3 +Help on built-in function kw_func3 in module example kkww__ffuunncc33(...) Signature : (data : unicode = u'Hello world!') -> NoneType -Help on built-in function kw_func4 +Help on built-in function kw_func4 in module example kkww__ffuunncc44(...) Signature : (myList : list = [13L, 17L]) -> NoneType diff --git a/example/example2.py b/example/example2.py index 422013473..f8bda4d58 100755 --- a/example/example2.py +++ b/example/example2.py @@ -3,6 +3,7 @@ from __future__ import print_function import sys, pydoc sys.path.append('.') +import example from example import Example2 Example2.value = 15 @@ -54,3 +55,9 @@ print(instance.pair_passthrough((True, "test"))) print(instance.tuple_passthrough((True, "test", 5))) print(pydoc.render_doc(Example2, "Help on %s")) + +print("__name__(example) = %s" % example.__name__) +print("__name__(example.Example2) = %s" % Example2.__name__) +print("__module__(example.Example2) = %s" % Example2.__module__) +print("__name__(example.Example2.get_set) = %s" % Example2.get_set.__name__) +print("__module__(example.Example2.get_set) = %s" % Example2.get_set.__module__) diff --git a/example/example2.ref b/example/example2.ref index a63c3cd81..08fb7ccc0 100644 --- a/example/example2.ref +++ b/example/example2.ref @@ -1,11 +1,15 @@ -key: key, value=value +15 +5 +example.Example2: No constructor defined! +can't set attribute key: key2, value=value2 key: key, value=value +key: key, value=value key: key2, value=value2 key: key3 -key: key1 key: key2 key: key1 +key: key1 key: key2 key: key3 Entry at positon 0: value @@ -13,107 +17,108 @@ list item 0: overwritten list item 1: value2 list item 0: value list item 1: value2 -15 -5 -example.Example2: No constructor defined! -can't set attribute This exception was intentionally thrown. -('test', True) -(5, 'test', True) +(u'test', True) +(5L, u'test', True) Help on class Example2 in module example -class EExxaammppllee22(builtins.object) +class EExxaammppllee22(__builtin__.object) | Example 2 documentation | | Methods defined here: | - | ____iinniitt____(self, /, *args, **kwargs) - | Initialize self. See help(type(self)) for accurate signature. + | ____iinniitt____(...) + | x.__init__(...) initializes x; see help(type(x)) for signature | - | ____nneeww____ = - | ggeett__ddiicctt(...) from builtins.PyCapsule + | ggeett__ddiicctt(...) | Signature : (example.Example2) -> dict | | Return a Python dictionary | - | ggeett__ddiicctt__22(...) from builtins.PyCapsule - | Signature : (example.Example2) -> dict + | ggeett__ddiicctt__22(...) + | Signature : (example.Example2) -> dict | | Return a C++ dictionary | - | ggeett__lliisstt(...) from builtins.PyCapsule + | ggeett__lliisstt(...) | Signature : (example.Example2) -> list | | Return a Python list | - | ggeett__lliisstt__22(...) from builtins.PyCapsule - | Signature : (example.Example2) -> list + | ggeett__lliisstt__22(...) + | Signature : (example.Example2) -> list | | Return a C++ list | - | ggeett__sseett(...) from builtins.PyCapsule + | ggeett__sseett(...) | Signature : (example.Example2) -> set | | Return a Python set | - | ggeett__sseett22(...) from builtins.PyCapsule + | ggeett__sseett22(...) | Signature : (example.Example2) -> set | | Return a C++ set | - | nneeww__iinnssttaannccee(...) from builtins.PyCapsule - | Signature : () -> example.Example2 - | - | Return an instance - | - | ppaaiirr__ppaasssstthhrroouugghh(...) from builtins.PyCapsule - | Signature : (example.Example2, (bool, str)) -> (str, bool) + | ppaaiirr__ppaasssstthhrroouugghh(...) + | Signature : (example.Example2, (bool, unicode)) -> (unicode, bool) | | Return a pair in reversed order | - | pprriinntt__ddiicctt(...) from builtins.PyCapsule - | Signature : (example.Example2, dict) -> None + | pprriinntt__ddiicctt(...) + | Signature : (example.Example2, dict) -> NoneType | | Print entries of a Python dictionary | - | pprriinntt__ddiicctt__22(...) from builtins.PyCapsule - | Signature : (example.Example2, dict) -> None + | pprriinntt__ddiicctt__22(...) + | Signature : (example.Example2, dict) -> NoneType | | Print entries of a C++ dictionary | - | pprriinntt__lliisstt(...) from builtins.PyCapsule - | Signature : (example.Example2, list) -> None + | pprriinntt__lliisstt(...) + | Signature : (example.Example2, list) -> NoneType | | Print entries of a Python list | - | pprriinntt__lliisstt__22(...) from builtins.PyCapsule - | Signature : (example.Example2, list) -> None + | pprriinntt__lliisstt__22(...) + | Signature : (example.Example2, list) -> NoneType | | Print entries of a C++ list | - | pprriinntt__sseett(...) from builtins.PyCapsule - | Signature : (example.Example2, set) -> None + | pprriinntt__sseett(...) + | Signature : (example.Example2, set) -> NoneType | | Print entries of a Python set | - | pprriinntt__sseett__22(...) from builtins.PyCapsule - | Signature : (example.Example2, set) -> None + | pprriinntt__sseett__22(...) + | Signature : (example.Example2, set) -> NoneType | | Print entries of a C++ set | - | tthhrrooww__eexxcceeppttiioonn(...) from builtins.PyCapsule - | Signature : (example.Example2) -> None + | tthhrrooww__eexxcceeppttiioonn(...) + | Signature : (example.Example2) -> NoneType | | Throw an exception | - | ttuuppllee__ppaasssstthhrroouugghh(...) from builtins.PyCapsule - | Signature : (example.Example2, (bool, str, int)) -> (int, str, bool) + | ttuuppllee__ppaasssstthhrroouugghh(...) + | Signature : (example.Example2, (bool, unicode, int)) -> (int, unicode, bool) | | Return a triple in reversed order | | ---------------------------------------------------------------------- | Data and other attributes defined here: | - | ____ppyybbiinndd1111____ = + | ____nneeww____ = + | T.__new__(S, ...) -> a new object with type S, a subtype of T + | + | nneeww__iinnssttaannccee = + | Signature : () -> example.Example2 + | + | Return an instance +__name__(example) = example +__name__(example.Example2) = Example2 +__module__(example.Example2) = example +__name__(example.Example2.get_set) = get_set +__module__(example.Example2.get_set) = example Destructing Example2 diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 6eb8ac86a..92fceeb4c 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -36,6 +36,9 @@ template arg_t arg::operator=(const T &value) { return arg_t( /// Annotation for methods struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; +/// Annotation for parent scope +struct scope { handle value; scope(const handle &s) : value(s) { } }; + /// Annotation for documentation struct doc { const char *value; doc(const char *value) : value(value) { } }; @@ -105,6 +108,9 @@ struct function_record { /// Python handle to the associated class (if this is method) handle class_; + /// Python handle to the parent scope (a class or a module) + handle scope; + /// Python handle to the sibling function representing an overload chain handle sibling; @@ -190,9 +196,15 @@ template <> struct process_attribute : process_attribute_default struct process_attribute : process_attribute_default { - static void init(const is_method &s, function_record *r) { r->class_ = s.class_; } + static void init(const is_method &s, function_record *r) { r->class_ = s.class_; r->scope = s.class_; } }; +/// Process an attribute which indicates the parent scope of a method +template <> struct process_attribute : process_attribute_default { + static void init(const scope &s, function_record *r) { r->scope = s.value; } +}; + + /// Process a keyword argument attribute (*without* a default value) template <> struct process_attribute : process_attribute_default { static void init(const arg &a, function_record *r) { diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b6de43116..02b3b7cca 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -263,10 +263,19 @@ protected: rec->def->ml_name = rec->name; rec->def->ml_meth = reinterpret_cast(*dispatcher); rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; + capsule rec_capsule(rec, [](PyObject *o) { destruct((detail::function_record *) PyCapsule_GetPointer(o, nullptr)); }); - m_ptr = PyCFunction_New(rec->def, rec_capsule.ptr()); + + object scope_module; + if (rec->scope) { + scope_module = (object) rec->scope.attr("__module__"); + if (!scope_module) + scope_module = (object) rec->scope.attr("__name__"); + } + + m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr()); if (!m_ptr) pybind11_fail("cpp_function::cpp_function(): Could not allocate function object"); } else { @@ -467,7 +476,7 @@ public: template module &def(const char *name_, Func &&f, const Extra& ... extra) { cpp_function func(std::forward(f), name(name_), - sibling((handle) attr(name_)), extra...); + sibling((handle) attr(name_)), scope(*this), extra...); /* PyModule_AddObject steals a reference to 'func' */ PyModule_AddObject(ptr(), name_, func.inc_ref().ptr()); return *this; @@ -742,26 +751,26 @@ public: template class_ & def_static(const char *name_, Func f, const Extra&... extra) { cpp_function cf(std::forward(f), name(name_), - sibling(attr(name_)), extra...); + sibling(attr(name_)), scope(*this), extra...); attr(cf.name()) = cf; return *this; } template class_ &def(const detail::op_ &op, const Extra&... extra) { - op.template execute(*this, extra...); + op.template execute(*this, is_method(*this), extra...); return *this; } template class_ & def_cast(const detail::op_ &op, const Extra&... extra) { - op.template execute_cast(*this, extra...); + op.template execute_cast(*this, is_method(*this), extra...); return *this; } template class_ &def(const detail::init &init, const Extra&... extra) { - init.template execute(*this, extra...); + init.template execute(*this, is_method(*this), extra...); return *this; } @@ -800,8 +809,8 @@ public: template class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) { cpp_function fget([pm](object) -> const D &{ return *pm; }, - return_value_policy::reference_internal, extra...), - fset([pm](object, const D &value) { *pm = value; }, extra...); + return_value_policy::reference_internal, scope(*this), extra...), + fset([pm](object, const D &value) { *pm = value; }, scope(*this), extra...); def_property_static(name, fget, fset); return *this; } @@ -809,7 +818,7 @@ public: template class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) { cpp_function fget([pm](object) -> const D &{ return *pm; }, - return_value_policy::reference_internal, extra...); + return_value_policy::reference_internal, scope(*this), extra...); def_property_readonly_static(name, fget); return *this; }