// See if we can find an attribute in the Qt meta-type system. This is // primarily to support access to JavaScript (e.g. QDeclarativeItem) so we // don't support overloads. PyObject *qpycore_qobject_getattr(QObject *qobj, PyObject *py_qobj, const char *name) { const QMetaObject *mo = qobj->metaObject(); // Try and find a method with the name. QMetaMethod method; int method_index = -1; // Count down to allow overrides (assuming they are possible). for (int m = mo->methodCount() - 1; m >= 0; --m) { method = mo->method(m); #if QT_VERSION >= 0x040500 if (method.methodType() == QMetaMethod::Constructor) continue; #endif // Get the method name. #if QT_VERSION >= 0x050000 QByteArray mname(method.methodSignature()); #else QByteArray mname(method.signature()); #endif int idx = mname.indexOf('('); if (idx >= 0) mname.truncate(idx); if (mname == name) { method_index = m; break; } } if (method_index < 0) { // Replicate the standard Python exception. PyErr_Format(PyExc_AttributeError, "'%s' object has no attribute '%s'", Py_TYPE(py_qobj)->tp_name, name); return 0; } // Get the value to return. Note that this is recreated each time. We // could put a descriptor in the type dictionary to satisfy the request in // future but the typical use case is getting a value from a C++ proxy // (e.g. QDeclarativeItem) and we can't assume that what is being proxied // is the same each time. PyObject *value; if (method.methodType() == QMetaMethod::Signal) { // We need to keep explicit references to the unbound signals (because // we don't use the type dictionary to do so) because they own the // parsed signature which may be needed by a PyQtProxy at some point. typedef QHash<QByteArray, PyObject *> SignalHash; static SignalHash *sig_hash = 0; // For crappy compilers. if (!sig_hash) sig_hash = new SignalHash; PyObject *sig_obj; #if QT_VERSION >= 0x050000 QByteArray sig_str(method.methodSignature()); #else QByteArray sig_str(method.signature()); #endif SignalHash::const_iterator it = sig_hash->find(sig_str); if (it == sig_hash->end()) { sig_obj = (PyObject *)qpycore_pyqtSignal_New(sig_str.constData()); if (!sig_obj) return 0; sig_hash->insert(sig_str, sig_obj); } else { sig_obj = it.value(); } value = qpycore_pyqtBoundSignal_New((qpycore_pyqtSignal *)sig_obj, py_qobj, qobj); } else { QByteArray py_name(Py_TYPE(py_qobj)->tp_name); py_name.append('.'); py_name.append(name); value = qpycore_pyqtMethodProxy_New(qobj, method_index, py_name); } return value; }
void FunctionArguments::check() { if( m_args.size() > m_max_args ) { std::string msg = m_function_name; msg += "() takes exactly "; msg += int_to_string( m_max_args ); msg += " arguments ("; msg += int_to_string( m_args.size() ); msg += " given)"; throw Py::TypeError( msg ); } Py::Tuple::size_type t_i; // place all the positional args in the checked args dict for( t_i=0; t_i<m_args.size(); t_i++ ) { m_checked_args[ m_arg_desc[t_i].m_arg_name ] = m_args[t_i]; } // look for args by name in the kws dict for( t_i=0; t_i<m_max_args; t_i++ ) { const argument_description &arg_desc = m_arg_desc[t_i]; // check for duplicate if( m_kws.hasKey( arg_desc.m_arg_name ) ) { if( m_checked_args.hasKey( arg_desc.m_arg_name ) ) { std::string msg = m_function_name; msg += "() multiple values for keyword argument '"; msg += arg_desc.m_arg_name; msg += "'"; throw Py::TypeError( msg ); } m_checked_args[ arg_desc.m_arg_name ] = m_kws[ arg_desc.m_arg_name ]; } } // check for names we dont known about Py::List::size_type l_i; Py::List names( m_kws.keys() ); for( l_i=0; l_i< names.length(); l_i++ ) { bool found = false; Py::String py_name( names[l_i] ); std::string name( py_name.as_std_string( g_utf_8 ) ); for( t_i=0; t_i<m_max_args; t_i++ ) { if( name == m_arg_desc[t_i].m_arg_name ) { found = true; break; } } if( !found ) { std::string msg = m_function_name; msg += "() got an unexpected keyword argument '"; msg += name; msg += "'"; throw Py::TypeError( msg ); } } // check for min args for( t_i=0; t_i<m_min_args; t_i++ ) { const argument_description &arg_desc = m_arg_desc[t_i]; // check for duplicate if( !m_checked_args.hasKey( arg_desc.m_arg_name ) ) { std::string msg = m_function_name; msg += "() required argument '"; msg += arg_desc.m_arg_name; msg += "'"; throw Py::TypeError( msg ); } } }