From 2ba0b2283182132d8ddaa3c543ba8813036a1f81 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 1 Nov 2000 02:30:37 +0000 Subject: [PATCH] const-ify ClassBase::getattr() Add repr() function to Class Add to_python/from_python conversions for PyPtr Standardize set_item/get_item interfaces (instead of proxies) for Dict and List Add Reprable<> template to newtypes.h Fix a bug wherein the __module__ attribute would be lost for classes that have a default virtual function implementation. [SVN r8091] --- extclass.cpp | 8 ++++++++ newtypes.h | 33 +++++++++++++++++++++++++++++++++ objects.cpp | 41 ++++++++++++++++++++++++++++++++++------- objects.h | 11 ++++++++--- pyptr.h | 27 ++++++++++++++++++++++++++- subclass.cpp | 14 +++++++++++++- subclass.h | 8 ++++---- 7 files changed, 126 insertions(+), 16 deletions(-) diff --git a/extclass.cpp b/extclass.cpp index caee6a83..0e5e87af 100644 --- a/extclass.cpp +++ b/extclass.cpp @@ -379,6 +379,14 @@ void ExtensionClassBase::add_default_method(PyPtr method, const char* // clear our dict now. It will henceforth contain only default method // implementations. dict() = Dict(); + + // Copy the "__module__" attribute from the fake base class, if any + PyObject *module_name = PyDict_GetItemString(new_base->dict().get(), "__module__"); + if (module_name != 0 && PyString_Check(module_name)) + { + static String module_key("__module__", String::interned); + PyDict_SetItem(dict().get(), module_key.get(), module_name); + } } Function::add_to_namespace(method, name, dict().get()); } diff --git a/newtypes.h b/newtypes.h index bdfcfa13..6e757a64 100644 --- a/newtypes.h +++ b/newtypes.h @@ -181,6 +181,18 @@ class Setattrable : public Base int instance_setattr(PyObject* instance, const char* name, PyObject* value) const; }; +template +class Reprable : public Base +{ + public: + typedef Reprable Properties; // Convenience for derived class construction + typedef typename Base::Instance Instance; + Reprable(PyTypeObject* type_type, const char* name); + Reprable(PyTypeObject* type_type); + private: + PyObject* instance_repr(PyObject* instance) const; +}; + // // Member function definitions // @@ -261,6 +273,27 @@ int Setattrable::instance_setattr(PyObject* instance, const char* name, Py return Downcast(instance)->setattr(name, value); } +// Reprable +template +Reprable::Reprable(PyTypeObject* type_type, const char* name) + : Base(type_type, name) +{ + this->enable(repr); +} + +template +Reprable::Reprable(PyTypeObject* type_type) + : Base(type_type) +{ + this->enable(repr); +} + +template +PyObject* Reprable::instance_repr(PyObject* instance) const +{ + return Downcast(instance)->repr(); +} + namespace detail { struct AllMethods { diff --git a/objects.cpp b/objects.cpp index 5c4a1b8a..3f63bf31 100644 --- a/objects.cpp +++ b/objects.cpp @@ -210,7 +210,8 @@ bool Dict::accepts(Ptr p) void Dict::clear() { PyDict_Clear(get()); } -const Ptr& Dict::Proxy::operator=(const Ptr& rhs) { +const Ptr& Dict::Proxy::operator=(const Ptr& rhs) +{ if (PyDict_SetItem(m_dict.get(), m_key.get(), rhs.get()) == -1) throw ErrorAlreadySet(); return rhs; @@ -234,7 +235,7 @@ Ptr Dict::operator[](Ptr key) const { } -Ptr Dict::get_item(const Ptr& key, const Ptr& default_ /* = Ptr() */) +Ptr Dict::get_item(const Ptr& key, const Ptr& default_ /* = Ptr() */) const { PyObject* value_or_null = PyDict_GetItem(get(), key.get()); if (value_or_null == 0 && !PyErr_Occurred()) @@ -243,6 +244,17 @@ Ptr Dict::get_item(const Ptr& key, const Ptr& default_ /* = Ptr() */) return Ptr(value_or_null, Ptr::borrowed); // Will throw if there was another error } +void Dict::set_item(const Ptr& key, const Ptr& value) +{ + if (PyDict_SetItem(get(), key.get(), value.get()) == -1) + throw ErrorAlreadySet(); +} + +void Dict::set_item(const Object& key, const Ptr& value) +{ + set_item(key.reference(), value); +} + void Dict::erase(Ptr key) { if (PyDict_DelItem(get(), key.get()) == -1) throw ErrorAlreadySet(); @@ -264,7 +276,7 @@ Ptr Dict::operator[](const Object& key) const return this->operator[](key.reference()); } -Ptr Dict::get_item(const Object& key, Ptr default_) +Ptr Dict::get_item(const Object& key, Ptr default_) const { return this->get_item(key.reference(), default_); } @@ -402,10 +414,7 @@ Tuple List::as_tuple() const const Ptr& List::Proxy::operator=(const Ptr& rhs) { - int result = PyList_SetItem(m_list.get(), m_index, rhs.get()); - if (result == -1) - throw ErrorAlreadySet(); - Py_INCREF(rhs.get()); + m_list.set_item(m_index, rhs); return rhs; } @@ -414,6 +423,24 @@ List::Proxy::operator Ptr() const return Ptr(PyList_GetItem(m_list.get(), m_index), Ptr::borrowed); } +Ptr List::get_item(std::size_t pos) const +{ + return Ptr(PyList_GetItem(this->get(), pos), Ptr::borrowed); +} + +void List::set_item(std::size_t pos, Ptr rhs) +{ + int result = PyList_SetItem(this->get(), pos, rhs.get()); + if (result == -1) + throw ErrorAlreadySet(); + Py_INCREF(rhs.get()); +} + +void List::set_item(std::size_t pos, Object rhs) +{ + this->set_item(pos, rhs.reference()); +} + List::Proxy::Proxy(const Ptr& list, std::size_t index) : m_list(list), m_index(index) { diff --git a/objects.h b/objects.h index 4f54befc..9f15284c 100644 --- a/objects.h +++ b/objects.h @@ -87,6 +87,9 @@ class List : public Object std::size_t size(); Ptr operator[](std::size_t pos) const; Proxy operator[](std::size_t pos); + Ptr get_item(std::size_t pos) const; + void set_item(std::size_t pos, Ptr); + void set_item(std::size_t pos, Object); void insert(std::size_t index, Ptr item); void push_back(Ptr item); void append(Ptr item); @@ -155,14 +158,16 @@ class Dict : public Object Proxy operator[](Ptr key); Ptr operator[](Ptr key) const; - Ptr get_item(const Ptr& key, const Ptr& _default = Ptr()); + Ptr get_item(const Ptr& key, const Ptr& default_ = Ptr()) const; + void set_item(const Ptr& key, const Ptr& value); void erase(Ptr key); Proxy operator[](const Object& key); Ptr operator[](const Object& key) const; - Ptr get_item(const Object& key, Ptr default_ = Ptr()); + Ptr get_item(const Object& key, Ptr default_ = Ptr()) const; + void set_item(const Object& key, const Ptr& value); void erase(const Object& key); @@ -194,7 +199,7 @@ struct List::Proxy friend class List; Proxy(const Ptr& list, std::size_t index); private: - Ptr m_list; + List m_list; std::size_t m_index; }; diff --git a/pyptr.h b/pyptr.h index 6c62a03f..f6437f4a 100644 --- a/pyptr.h +++ b/pyptr.h @@ -19,9 +19,34 @@ namespace py { + +#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE +} +#endif + +template +struct PyPtrConversions : Base +{ + inline friend T from_python(PyObject* x, py::Type) + { return T(x, T::new_ref); } + + inline friend T from_python(PyObject* x, py::Type) + { return T(x, T::new_ref); } + + inline friend PyObject* to_python(T x) + { return x.release(); } + +}; + +#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE +namespace py { +using ::PyPtrConversions; +#endif + template class PyPtr - : public boost::dereferenceable, T*> // supplies op-> + : public PyPtrConversions, + boost::dereferenceable, T*> > // supplies op-> { public: PyPtr(const PyPtr& rhs) diff --git a/subclass.cpp b/subclass.cpp index 46c9a330..fce9f06f 100644 --- a/subclass.cpp +++ b/subclass.cpp @@ -87,7 +87,7 @@ namespace detail { m_bases = new_bases; } - PyObject* ClassBase::getattr(const char* name) + PyObject* ClassBase::getattr(const char* name) const { if (!PY_CSTD_::strcmp(name, "__dict__")) { @@ -153,6 +153,18 @@ namespace detail { return 0; } + // Mostly copied wholesale from Python's classobject.c + PyObject* ClassBase::repr() const + { + PyObject *mod = PyDict_GetItemString(m_name_space.get(), "__module__"); + unsigned long address = reinterpret_cast(this); + String result = (mod == NULL || !PyString_Check(mod)) + ? String("") % Tuple(m_name, address) + : String("") % Tuple(Ptr(mod, Ptr::borrowed), m_name, address); + return result.reference().release(); + } + + int ClassBase::setattr(const char* name, PyObject* value) { if (is_special_name(name) diff --git a/subclass.h b/subclass.h index 9bc05964..88689a61 100644 --- a/subclass.h +++ b/subclass.h @@ -92,9 +92,10 @@ namespace detail { Dict& dict(); // Standard Python functions. - PyObject* getattr(const char* name); + PyObject* getattr(const char* name) const; int setattr(const char* name, PyObject* value); - + PyObject* repr() const; + protected: bool initialize_instance(Instance* instance, PyObject* args, PyObject* keywords); void add_base(Ptr base); @@ -184,7 +185,7 @@ class Class // The type of a Class object. template class MetaClass - : public Callable > > > >, + : public Reprable > > > > >, boost::noncopyable { public: @@ -192,7 +193,6 @@ class MetaClass // Standard Python functions. PyObject* call(PyObject* args, PyObject* keywords); - private: struct TypeObject : Singleton > >