diff --git a/scripts/stubgen.py b/scripts/stubgen.py index fea989d1b..98943562d 100644 --- a/scripts/stubgen.py +++ b/scripts/stubgen.py @@ -310,9 +310,9 @@ def get_py_methods( ret_type = translate_ret_type(getter.ret_type()) doc = getter.doc() properties.append( - MethodStub( - decorator="@property", - signature=f"def {name}(self) -> ClassVar[{ret_type}]", + PropertyStub( + decorator="", + signature=f"{name}: ClassVar[{ret_type}]", name=name, docstring=doc, ) diff --git a/src/pya/pya/pyaInternal.cc b/src/pya/pya/pyaInternal.cc index cb348a764..88f973550 100644 --- a/src/pya/pya/pyaInternal.cc +++ b/src/pya/pya/pyaInternal.cc @@ -28,6 +28,8 @@ #include "tlLog.h" +#include + namespace pya { @@ -155,10 +157,14 @@ MethodTable::MethodTable (const gsi::ClassBase *cls_decl, PythonModule *module) if (! (*m)->is_callback () && ! (*m)->is_signal ()) { bool st = (*m)->is_static (); + bool no_args = ((*m)->end_arguments () == (*m)->begin_arguments ()); for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) { if (! syn->is_getter && ! syn->is_setter) { - if ((*m)->end_arguments () - (*m)->begin_arguments () == 0 && is_property_setter (st, syn->name) && ! is_property_getter (st, syn->name)) { + if (no_args && is_property_setter (st, syn->name) && ! is_property_getter (st, syn->name)) { + add_getter (syn->name, *m); + } else if (st && no_args && (isupper (syn->name [0]) || (*m)->is_const ())) { + // static methods without arguments which start with a capital letter are treated as constants add_getter (syn->name, *m); } else { if (syn->is_predicate && std::string (syn->name, 0, 3) == "is_") { diff --git a/src/pya/pya/pyaModule.cc b/src/pya/pya/pyaModule.cc index 862646160..611ae3a63 100644 --- a/src/pya/pya/pyaModule.cc +++ b/src/pya/pya/pyaModule.cc @@ -386,23 +386,23 @@ public: // produce the properties - if (! as_static) { + for (size_t mid = mt->bottom_property_mid (); mid < mt->top_property_mid (); ++mid) { - for (size_t mid = mt->bottom_property_mid (); mid < mt->top_property_mid (); ++mid) { + MethodTableEntry::method_iterator begin_setters = mt->begin_setters (mid); + MethodTableEntry::method_iterator end_setters = mt->end_setters (mid); + MethodTableEntry::method_iterator begin_getters = mt->begin_getters (mid); + MethodTableEntry::method_iterator end_getters = mt->end_getters (mid); + int setter_mid = begin_setters != end_setters ? int (mid) : -1; + int getter_mid = begin_getters != end_getters ? int (mid) : -1; - MethodTableEntry::method_iterator begin_setters = mt->begin_setters (mid); - MethodTableEntry::method_iterator end_setters = mt->end_setters (mid); - MethodTableEntry::method_iterator begin_getters = mt->begin_getters (mid); - MethodTableEntry::method_iterator end_getters = mt->end_getters (mid); - int setter_mid = begin_setters != end_setters ? int (mid) : -1; - int getter_mid = begin_getters != end_getters ? int (mid) : -1; + bool is_static = false; + if (begin_setters != end_setters) { + is_static = (*begin_setters)->is_static (); + } else if (begin_getters != end_getters) { + is_static = (*begin_getters)->is_static (); + } - bool is_static = false; - if (begin_setters != end_setters) { - is_static = (*begin_setters)->is_static (); - } else if (begin_getters != end_getters) { - is_static = (*begin_getters)->is_static (); - } + if (! as_static || is_static) { const std::string &name = mt->property_name (mid); @@ -479,65 +479,63 @@ public: } - // collect the names which have been disambiguated static/non-static wise - std::vector disambiguated_names; + if (! as_static) { - // produce the methods now - for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) { + // collect the names which have been disambiguated static/non-static wise + std::vector disambiguated_names; - if (! mt->is_enabled (mid)) { - continue; - } + // produce the methods now + for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) { - std::string name = mt->name (mid); - - // does this method hide a property? -> append "_" in that case - std::pair t = mt->find_property (mt->is_static (mid), name); - if (t.first) { - name += "_"; - } - - // needs static/non-static disambiguation? - t = mt->find_method (! mt->is_static (mid), name); - if (t.first) { - - disambiguated_names.push_back (name); - if (mt->is_static (mid)) { - name = "_class_" + name; - } else { - name = "_inst_" + name; + if (! mt->is_enabled (mid)) { + continue; } - mp_module->add_python_doc (*cls, mt, int (mid), tl::sprintf (tl::to_string (tr ("This attribute is available as '%s' in Python")), name)); + std::string name = mt->name (mid); - } else if (is_reserved_word (name)) { - - // drop non-standard names - if (tl::verbosity () >= 20) { - tl::warn << tl::to_string (tr ("Class ")) << cls->name () << ": " << tl::to_string (tr ("no Python mapping for method (reserved word) ")) << name; + // does this method hide a property? -> append "_" in that case + std::pair t = mt->find_property (mt->is_static (mid), name); + if (t.first) { + name += "_"; } - name += "_"; + // needs static/non-static disambiguation? + t = mt->find_method (! mt->is_static (mid), name); + if (t.first) { - mt->rename (mid, name); - mp_module->add_python_doc (*cls, mt, int (mid), tl::sprintf (tl::to_string (tr ("This attribute is available as '%s' in Python")), name)); + disambiguated_names.push_back (name); + if (mt->is_static (mid)) { + name = "_class_" + name; + } else { + name = "_inst_" + name; + } - } + mp_module->add_python_doc (*cls, mt, int (mid), tl::sprintf (tl::to_string (tr ("This attribute is available as '%s' in Python")), name)); + + } else if (is_reserved_word (name)) { + + // drop non-standard names + if (tl::verbosity () >= 20) { + tl::warn << tl::to_string (tr ("Class ")) << cls->name () << ": " << tl::to_string (tr ("no Python mapping for method (reserved word) ")) << name; + } + + name += "_"; + + mt->rename (mid, name); + mp_module->add_python_doc (*cls, mt, int (mid), tl::sprintf (tl::to_string (tr ("This attribute is available as '%s' in Python")), name)); - // create documentation - std::string doc; - for (MethodTableEntry::method_iterator m = mt->begin (mid); m != mt->end (mid); ++m) { - if (! doc.empty ()) { - doc = "\n\n"; } - doc += (*m)->doc (); - } - const gsi::MethodBase *m_first = *mt->begin (mid); + // create documentation + std::string doc; + for (MethodTableEntry::method_iterator m = mt->begin (mid); m != mt->end (mid); ++m) { + if (! doc.empty ()) { + doc = "\n\n"; + } + doc += (*m)->doc (); + } - if (! mt->is_static (mid)) { // Bound methods - - if (! as_static) { + if (! mt->is_static (mid)) { // Bound methods PyMethodDef *method = mp_module->make_method_def (); method->ml_name = mp_module->make_string (name); @@ -552,42 +550,21 @@ public: PythonRef attr = PythonRef (PyDescr_NewMethod (type, method)); set_type_attr (type, name, attr); - } + } else { // Class methods - } else if (isupper (name [0]) || m_first->is_const ()) { + PyMethodDef *method = mp_module->make_method_def (); + method->ml_name = mp_module->make_string (name); + method->ml_meth = (PyCFunction) get_method_adaptor (mid); + method->ml_doc = mp_module->make_string (doc); + method->ml_flags = METH_VARARGS | METH_CLASS; - if ((mt->end (mid) - mt->begin (mid)) == 1 && m_first->begin_arguments () == m_first->end_arguments ()) { - - // static methods without arguments which start with a capital letter are treated as constants - PYAStaticAttributeDescriptorObject *desc = PYAStaticAttributeDescriptorObject::create (mp_module->make_string (name)); - desc->type = type; - desc->getter = get_method_adaptor (mid); - - PythonRef attr (desc); + PythonRef attr = PythonRef (PyDescr_NewClassMethod (type, method)); set_type_attr (type, name, attr); - } else if (tl::verbosity () >= 20) { - tl::warn << "Upper case method name encountered which cannot be used as a Python constant (more than one overload or at least one argument): " << cls->name () << "." << name; - mp_module->add_python_doc (*cls, mt, int (mid), tl::to_string (tr ("This attribute is not available for Python"))); } - } else if (! as_static) { // Class methods - - PyMethodDef *method = mp_module->make_method_def (); - method->ml_name = mp_module->make_string (name); - method->ml_meth = (PyCFunction) get_method_adaptor (mid); - method->ml_doc = mp_module->make_string (doc); - method->ml_flags = METH_VARARGS | METH_CLASS; - - PythonRef attr = PythonRef (PyDescr_NewClassMethod (type, method)); - set_type_attr (type, name, attr); - } - } - - if (! as_static) { - // Complete the comparison operators if necessary. // Unlike Ruby, Python does not automatically implement != from == for example. // We assume that "==" and "<" are the minimum requirements for full comparison @@ -663,44 +640,44 @@ public: } - } + // install the static/non-static dispatcher descriptor - // install the static/non-static dispatcher descriptor + std::sort (disambiguated_names.begin (), disambiguated_names.end ()); + disambiguated_names.erase (std::unique (disambiguated_names.begin (), disambiguated_names.end ()), disambiguated_names.end ()); - std::sort (disambiguated_names.begin (), disambiguated_names.end ()); - disambiguated_names.erase (std::unique (disambiguated_names.begin (), disambiguated_names.end ()), disambiguated_names.end ()); + for (std::vector::const_iterator a = disambiguated_names.begin (); a != disambiguated_names.end (); ++a) { - for (std::vector::const_iterator a = disambiguated_names.begin (); a != disambiguated_names.end (); ++a) { - - std::pair pa; - pa = mt->find_method (true, *a); - if (pa.first) { - mt->alias (pa.second, "_class_" + *a); - } - pa = mt->find_method (false, *a); - if (pa.first) { - mt->alias (pa.second, "_inst_" + *a); - } - - PyObject *attr_inst = PyObject_GetAttrString ((PyObject *) type, ("_inst_" + *a).c_str ()); - PyObject *attr_class = PyObject_GetAttrString ((PyObject *) type, ("_class_" + *a).c_str ()); - if (attr_inst == NULL || attr_class == NULL) { - - // some error -> don't install the disambiguator - Py_XDECREF (attr_inst); - Py_XDECREF (attr_class); - PyErr_Clear (); - - if (tl::verbosity () >= 20) { - tl::warn << "Unable to install a static/non-static disambiguator for " << *a << " in class " << cls->name (); + std::pair pa; + pa = mt->find_method (true, *a); + if (pa.first) { + mt->alias (pa.second, "_class_" + *a); + } + pa = mt->find_method (false, *a); + if (pa.first) { + mt->alias (pa.second, "_inst_" + *a); } - } else { + PyObject *attr_inst = PyObject_GetAttrString ((PyObject *) type, ("_inst_" + *a).c_str ()); + PyObject *attr_class = PyObject_GetAttrString ((PyObject *) type, ("_class_" + *a).c_str ()); + if (attr_inst == NULL || attr_class == NULL) { - PyObject *desc = PYAAmbiguousMethodDispatcher::create (attr_inst, attr_class); - PythonRef name (c2python (*a)); - // Note: we use GenericSetAttr since that one allows us setting attributes on built-in types - PyObject_GenericSetAttr ((PyObject *) type, name.get (), desc); + // some error -> don't install the disambiguator + Py_XDECREF (attr_inst); + Py_XDECREF (attr_class); + PyErr_Clear (); + + if (tl::verbosity () >= 20) { + tl::warn << "Unable to install a static/non-static disambiguator for " << *a << " in class " << cls->name (); + } + + } else { + + PyObject *desc = PYAAmbiguousMethodDispatcher::create (attr_inst, attr_class); + PythonRef name (c2python (*a)); + // Note: we use GenericSetAttr since that one allows us setting attributes on built-in types + PyObject_GenericSetAttr ((PyObject *) type, name.get (), desc); + + } }