mirror of https://github.com/KLayout/klayout.git
Class properties
This commit is contained in:
parent
eb31f67aeb
commit
9011af54ac
|
|
@ -310,9 +310,9 @@ def get_py_methods(
|
||||||
ret_type = translate_ret_type(getter.ret_type())
|
ret_type = translate_ret_type(getter.ret_type())
|
||||||
doc = getter.doc()
|
doc = getter.doc()
|
||||||
properties.append(
|
properties.append(
|
||||||
MethodStub(
|
PropertyStub(
|
||||||
decorator="@property",
|
decorator="",
|
||||||
signature=f"def {name}(self) -> ClassVar[{ret_type}]",
|
signature=f"{name}: ClassVar[{ret_type}]",
|
||||||
name=name,
|
name=name,
|
||||||
docstring=doc,
|
docstring=doc,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include "tlLog.h"
|
#include "tlLog.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
namespace pya
|
namespace pya
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -155,10 +157,14 @@ MethodTable::MethodTable (const gsi::ClassBase *cls_decl, PythonModule *module)
|
||||||
if (! (*m)->is_callback () && ! (*m)->is_signal ()) {
|
if (! (*m)->is_callback () && ! (*m)->is_signal ()) {
|
||||||
|
|
||||||
bool st = (*m)->is_static ();
|
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) {
|
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||||
if (! syn->is_getter && ! syn->is_setter) {
|
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);
|
add_getter (syn->name, *m);
|
||||||
} else {
|
} else {
|
||||||
if (syn->is_predicate && std::string (syn->name, 0, 3) == "is_") {
|
if (syn->is_predicate && std::string (syn->name, 0, 3) == "is_") {
|
||||||
|
|
|
||||||
|
|
@ -386,23 +386,23 @@ public:
|
||||||
|
|
||||||
// produce the properties
|
// 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);
|
bool is_static = false;
|
||||||
MethodTableEntry::method_iterator end_setters = mt->end_setters (mid);
|
if (begin_setters != end_setters) {
|
||||||
MethodTableEntry::method_iterator begin_getters = mt->begin_getters (mid);
|
is_static = (*begin_setters)->is_static ();
|
||||||
MethodTableEntry::method_iterator end_getters = mt->end_getters (mid);
|
} else if (begin_getters != end_getters) {
|
||||||
int setter_mid = begin_setters != end_setters ? int (mid) : -1;
|
is_static = (*begin_getters)->is_static ();
|
||||||
int getter_mid = begin_getters != end_getters ? int (mid) : -1;
|
}
|
||||||
|
|
||||||
bool is_static = false;
|
if (! as_static || is_static) {
|
||||||
if (begin_setters != end_setters) {
|
|
||||||
is_static = (*begin_setters)->is_static ();
|
|
||||||
} else if (begin_getters != end_getters) {
|
|
||||||
is_static = (*begin_getters)->is_static ();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &name = mt->property_name (mid);
|
const std::string &name = mt->property_name (mid);
|
||||||
|
|
||||||
|
|
@ -479,65 +479,63 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect the names which have been disambiguated static/non-static wise
|
if (! as_static) {
|
||||||
std::vector<std::string> disambiguated_names;
|
|
||||||
|
|
||||||
// produce the methods now
|
// collect the names which have been disambiguated static/non-static wise
|
||||||
for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) {
|
std::vector<std::string> disambiguated_names;
|
||||||
|
|
||||||
if (! mt->is_enabled (mid)) {
|
// produce the methods now
|
||||||
continue;
|
for (size_t mid = mt->bottom_mid (); mid < mt->top_mid (); ++mid) {
|
||||||
}
|
|
||||||
|
|
||||||
std::string name = mt->name (mid);
|
if (! mt->is_enabled (mid)) {
|
||||||
|
continue;
|
||||||
// does this method hide a property? -> append "_" in that case
|
|
||||||
std::pair<bool, size_t> 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
// does this method hide a property? -> append "_" in that case
|
||||||
|
std::pair<bool, size_t> t = mt->find_property (mt->is_static (mid), name);
|
||||||
// drop non-standard names
|
if (t.first) {
|
||||||
if (tl::verbosity () >= 20) {
|
name += "_";
|
||||||
tl::warn << tl::to_string (tr ("Class ")) << cls->name () << ": " << tl::to_string (tr ("no Python mapping for method (reserved word) ")) << name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name += "_";
|
// needs static/non-static disambiguation?
|
||||||
|
t = mt->find_method (! mt->is_static (mid), name);
|
||||||
|
if (t.first) {
|
||||||
|
|
||||||
mt->rename (mid, name);
|
disambiguated_names.push_back (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));
|
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 (! mt->is_static (mid)) { // Bound methods
|
||||||
|
|
||||||
if (! as_static) {
|
|
||||||
|
|
||||||
PyMethodDef *method = mp_module->make_method_def ();
|
PyMethodDef *method = mp_module->make_method_def ();
|
||||||
method->ml_name = mp_module->make_string (name);
|
method->ml_name = mp_module->make_string (name);
|
||||||
|
|
@ -552,42 +550,21 @@ public:
|
||||||
PythonRef attr = PythonRef (PyDescr_NewMethod (type, method));
|
PythonRef attr = PythonRef (PyDescr_NewMethod (type, method));
|
||||||
set_type_attr (type, name, attr);
|
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 ()) {
|
PythonRef attr = PythonRef (PyDescr_NewClassMethod (type, method));
|
||||||
|
|
||||||
// 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);
|
|
||||||
set_type_attr (type, name, attr);
|
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.
|
// Complete the comparison operators if necessary.
|
||||||
// Unlike Ruby, Python does not automatically implement != from == for example.
|
// Unlike Ruby, Python does not automatically implement != from == for example.
|
||||||
// We assume that "==" and "<" are the minimum requirements for full comparison
|
// 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 ());
|
for (std::vector<std::string>::const_iterator a = disambiguated_names.begin (); a != disambiguated_names.end (); ++a) {
|
||||||
disambiguated_names.erase (std::unique (disambiguated_names.begin (), disambiguated_names.end ()), disambiguated_names.end ());
|
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator a = disambiguated_names.begin (); a != disambiguated_names.end (); ++a) {
|
std::pair<bool, size_t> pa;
|
||||||
|
pa = mt->find_method (true, *a);
|
||||||
std::pair<bool, size_t> pa;
|
if (pa.first) {
|
||||||
pa = mt->find_method (true, *a);
|
mt->alias (pa.second, "_class_" + *a);
|
||||||
if (pa.first) {
|
}
|
||||||
mt->alias (pa.second, "_class_" + *a);
|
pa = mt->find_method (false, *a);
|
||||||
}
|
if (pa.first) {
|
||||||
pa = mt->find_method (false, *a);
|
mt->alias (pa.second, "_inst_" + *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 ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} 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);
|
// some error -> don't install the disambiguator
|
||||||
PythonRef name (c2python (*a));
|
Py_XDECREF (attr_inst);
|
||||||
// Note: we use GenericSetAttr since that one allows us setting attributes on built-in types
|
Py_XDECREF (attr_class);
|
||||||
PyObject_GenericSetAttr ((PyObject *) type, name.get (), desc);
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue