Make sipify responsible for QList<enum> conversion code insertion

This commit is contained in:
Nyall Dawson 2025-09-01 09:24:43 +10:00
parent 0f9e56d475
commit 653871b8f5
10 changed files with 142 additions and 220 deletions

View File

@ -2439,7 +2439,8 @@ EXPAND_AS_DEFINED = "SIP_ABSTRACT" \
"SIP_MONKEYPATCH_COMPAT_NAME" \
"SIP_MONKEYPATCH_SCOPEENUM" \
"SIP_MONKEYPATCH_SCOPEENUM_UNNEST" \
"SIP_MONKEYPATCH_FLAGS_UNNEST"
"SIP_MONKEYPATCH_FLAGS_UNNEST" \
"SIP_INSERT_QLIST_ENUM_CONVERSION_CODE"
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all references to function-like macros that are alone on a line, have

View File

@ -391,11 +391,10 @@ setCaChain set the CA chain
%MappedType QList<QSslError::SslError>
/ TypeHintIn = "Iterable[QSslError.SslError]",
TypeHintOut = "List[QSslError.SslError]", TypeHintValue = "[]" /
%MappedType QList<QSslError::SslError> /TypeHintIn = "Iterable[QSslError.SslError]",TypeHintOut = "List[QSslError.SslError]", TypeHintValue = "[]"/
{
%TypeHeaderCode
#include <QList>
#include <QSslError>
%End
@ -407,8 +406,7 @@ setCaChain set the CA chain
for ( int i = 0; i < sipCpp->size(); ++i )
{
PyObject *eobj = sipConvertFromEnum( static_cast<int>( sipCpp->at( i ) ),
sipType_QSslError_SslError );
PyObject *eobj = sipConvertFromEnum( static_cast<int>( sipCpp->at( i ) ), sipType_QSslError_SslError );
if ( !eobj )
{
@ -443,7 +441,7 @@ setCaChain set the CA chain
QList<QSslError::SslError> *ql = new QList<QSslError::SslError>;
for ( Py_ssize_t i = 0; ; ++i )
for ( Py_ssize_t i = 0;; ++i )
{
PyErr_Clear();
PyObject *itm = PyIter_Next( iter );
@ -466,9 +464,7 @@ setCaChain set the CA chain
if ( PyErr_Occurred() )
{
PyErr_Format( PyExc_TypeError,
"index %zd has type '%s' but 'QSslError.SslError' is expected",
i, sipPyTypeName( Py_TYPE( itm ) ) );
PyErr_Format( PyExc_TypeError, "index %zd has type '%s' but 'QSslError.SslError' is expected", i, sipPyTypeName( Py_TYPE( itm ) ) );
Py_DECREF( itm );
delete ql;
@ -492,7 +488,6 @@ setCaChain set the CA chain
};
class QgsAuthConfigSslServer
{
%Docstring(signature="appended")

View File

@ -10,6 +10,7 @@
%MappedType QList<QgsSearchWidgetWrapper::FilterFlag> /TypeHintIn = "Iterable[QgsSearchWidgetWrapper.FilterFlag]",TypeHintOut = "List[QgsSearchWidgetWrapper.FilterFlag]", TypeHintValue = "[]"/
{
%TypeHeaderCode
@ -104,6 +105,8 @@
return sipGetState( sipTransferObj );
%End
};
class QgsSearchWidgetWrapper : QgsWidgetWrapper
{
%Docstring(signature="appended")

View File

@ -391,11 +391,10 @@ setCaChain set the CA chain
%MappedType QList<QSslError::SslError>
/ TypeHintIn = "Iterable[QSslError.SslError]",
TypeHintOut = "List[QSslError.SslError]", TypeHintValue = "[]" /
%MappedType QList<QSslError::SslError> /TypeHintIn = "Iterable[QSslError.SslError]",TypeHintOut = "List[QSslError.SslError]", TypeHintValue = "[]"/
{
%TypeHeaderCode
#include <QList>
#include <QSslError>
%End
@ -407,8 +406,7 @@ setCaChain set the CA chain
for ( int i = 0; i < sipCpp->size(); ++i )
{
PyObject *eobj = sipConvertFromEnum( static_cast<int>( sipCpp->at( i ) ),
sipType_QSslError_SslError );
PyObject *eobj = sipConvertFromEnum( static_cast<int>( sipCpp->at( i ) ), sipType_QSslError_SslError );
if ( !eobj )
{
@ -443,7 +441,7 @@ setCaChain set the CA chain
QList<QSslError::SslError> *ql = new QList<QSslError::SslError>;
for ( Py_ssize_t i = 0; ; ++i )
for ( Py_ssize_t i = 0;; ++i )
{
PyErr_Clear();
PyObject *itm = PyIter_Next( iter );
@ -466,9 +464,7 @@ setCaChain set the CA chain
if ( PyErr_Occurred() )
{
PyErr_Format( PyExc_TypeError,
"index %zd has type '%s' but 'QSslError.SslError' is expected",
i, sipPyTypeName( Py_TYPE( itm ) ) );
PyErr_Format( PyExc_TypeError, "index %zd has type '%s' but 'QSslError.SslError' is expected", i, sipPyTypeName( Py_TYPE( itm ) ) );
Py_DECREF( itm );
delete ql;
@ -492,7 +488,6 @@ setCaChain set the CA chain
};
class QgsAuthConfigSslServer
{
%Docstring(signature="appended")

View File

@ -10,6 +10,7 @@
%MappedType QList<QgsSearchWidgetWrapper::FilterFlag> /TypeHintIn = "Iterable[QgsSearchWidgetWrapper.FilterFlag]",TypeHintOut = "List[QgsSearchWidgetWrapper.FilterFlag]", TypeHintValue = "[]"/
{
%TypeHeaderCode
@ -104,6 +105,8 @@
return sipGetState( sipTransferObj );
%End
};
class QgsSearchWidgetWrapper : QgsWidgetWrapper
{
%Docstring(signature="appended")

View File

@ -36,6 +36,7 @@ cppcheck --library=qt.cfg --inline-suppr \
-DSIP_FACTORY= \
-DSIP_PYNAME= \
-DSIP_THROW= \
-DSIP_INSERT_QLIST_ENUM_CONVERSION_CODE= \
-DFINAL="final" \
-DCMAKE_SOURCE_DIR="/foo/bar" \
-DQ_NOWARN_DEPRECATED_PUSH= \

View File

@ -555,6 +555,103 @@ CLASS_HEADERFILES = {
"QgsSettingsEntryBaseTemplate": "qgssettingsentry.h",
}
QLIST_ENUM_CONVERSION_CODE = """
%MappedType QList<{class_name}::{enum_name}> /TypeHintIn = "Iterable[{class_name}.{enum_name}]",TypeHintOut = "List[{class_name}.{enum_name}]", TypeHintValue = "[]"/
{{
%TypeHeaderCode
#include <QList>{extra_includes}
%End
%ConvertFromTypeCode
PyObject *l = PyList_New( sipCpp->size() );
if ( !l )
return 0;
for ( int i = 0; i < sipCpp->size(); ++i )
{{
PyObject *eobj = sipConvertFromEnum( static_cast<int>( sipCpp->at( i ) ), sipType_{class_name}_{enum_name} );
if ( !eobj )
{{
Py_DECREF( l );
return 0;
}}
PyList_SetItem( l, i, eobj );
}}
return l;
%End
%ConvertToTypeCode
PyObject *iter = PyObject_GetIter( sipPy );
if ( !sipIsErr )
{{
PyErr_Clear();
Py_XDECREF( iter );
return ( iter && !PyBytes_Check( sipPy ) && !PyUnicode_Check( sipPy ) );
}}
if ( !iter )
{{
*sipIsErr = 1;
return 0;
}}
QList<{class_name}::{enum_name}> *ql = new QList<{class_name}::{enum_name}>;
for ( Py_ssize_t i = 0;; ++i )
{{
PyErr_Clear();
PyObject *itm = PyIter_Next( iter );
if ( !itm )
{{
if ( PyErr_Occurred() )
{{
delete ql;
Py_DECREF( iter );
*sipIsErr = 1;
return 0;
}}
break;
}}
int v = sipConvertToEnum( itm, sipType_{class_name}_{enum_name} );
if ( PyErr_Occurred() )
{{
PyErr_Format( PyExc_TypeError, "index %zd has type '%s' but '{class_name}.{enum_name}' is expected", i, sipPyTypeName( Py_TYPE( itm ) ) );
Py_DECREF( itm );
delete ql;
Py_DECREF( iter );
*sipIsErr = 1;
return 0;
}}
ql->append( static_cast<{class_name}::{enum_name}>( v ) );
Py_DECREF( itm );
}}
Py_DECREF( iter );
*sipCppPtr = ql;
return sipGetState( sipTransferObj );
%End
}};
"""
def replace_macros(line):
line = re.sub(r"\bTRUE\b", "``True``", line)
@ -1649,6 +1746,23 @@ def try_process_sip_directive():
dbg_info("found SIP_WHEN_FEATURE")
CONTEXT.if_feature_condition = match.group(1)
match = re.search(
r"^\s*SIP_INSERT_QLIST_ENUM_CONVERSION_CODE\(\s*(.*?)::(.*?)\s*,\s*\"(.*?)\"\s*\)\s*;?\s*$",
CONTEXT.current_line,
)
if match:
class_name = match.group(1)
enum_name = match.group(2)
extra_includes = match.group(3)
if extra_includes:
extra_includes = f"\n#include {extra_includes}"
sip_convert_code = QLIST_ENUM_CONVERSION_CODE.format(
class_name=class_name, enum_name=enum_name, extra_includes=extra_includes
)
write_output("SCC", sip_convert_code)
CONTEXT.current_line = ""
match = re.search(r'SIP_TYPEHEADER_INCLUDE\(\s*"(.*?)"\s*\)', CONTEXT.current_line)
if match:
dbg_info("found SIP_TYPEHEADER_INCLUDE")

View File

@ -330,110 +330,7 @@ class CORE_EXPORT QgsPkiConfigBundle
};
#ifdef SIP_RUN
% MappedType QList<QSslError::SslError>
/ TypeHintIn = "Iterable[QSslError.SslError]",
TypeHintOut = "List[QSslError.SslError]", TypeHintValue = "[]" /
{
% TypeHeaderCode
#include <QSslError>
% End
% ConvertFromTypeCode
PyObject *l = PyList_New( sipCpp->size() );
if ( !l )
return 0;
for ( int i = 0; i < sipCpp->size(); ++i )
{
PyObject *eobj = sipConvertFromEnum( static_cast<int>( sipCpp->at( i ) ),
sipType_QSslError_SslError );
if ( !eobj )
{
Py_DECREF( l );
return 0;
}
PyList_SetItem( l, i, eobj );
}
return l;
% End
% ConvertToTypeCode
PyObject *iter = PyObject_GetIter( sipPy );
if ( !sipIsErr )
{
PyErr_Clear();
Py_XDECREF( iter );
return ( iter && !PyBytes_Check( sipPy ) && !PyUnicode_Check( sipPy ) );
}
if ( !iter )
{
*sipIsErr = 1;
return 0;
}
QList<QSslError::SslError> *ql = new QList<QSslError::SslError>;
for ( Py_ssize_t i = 0; ; ++i )
{
PyErr_Clear();
PyObject *itm = PyIter_Next( iter );
if ( !itm )
{
if ( PyErr_Occurred() )
{
delete ql;
Py_DECREF( iter );
*sipIsErr = 1;
return 0;
}
break;
}
int v = sipConvertToEnum( itm, sipType_QSslError_SslError );
if ( PyErr_Occurred() )
{
PyErr_Format( PyExc_TypeError,
"index %zd has type '%s' but 'QSslError.SslError' is expected",
i, sipPyTypeName( Py_TYPE( itm ) ) );
Py_DECREF( itm );
delete ql;
Py_DECREF( iter );
*sipIsErr = 1;
return 0;
}
ql->append( static_cast<QSslError::SslError>( v ) );
Py_DECREF( itm );
}
Py_DECREF( iter );
*sipCppPtr = ql;
return sipGetState( sipTransferObj );
% End
};
#endif
SIP_INSERT_QLIST_ENUM_CONVERSION_CODE( QSslError::SslError, "<QSslError>" );
/**
* \ingroup core

View File

@ -300,4 +300,11 @@
*/
#define SIP_TYPEHEADER_INCLUDE(file)
/*
* Inserts sip conversion code for QList<class_name::enum_name>, where class_name::enum_name is a c++ enum.
*
* extra_includes is an optional argument containing extra headers to include in the conversion code. Set to "" if not required.
*/
#define SIP_INSERT_QLIST_ENUM_CONVERSION_CODE(class_name, extra_includes)
#endif // QGIS_SIP_H

View File

@ -28,102 +28,8 @@ class QgsField;
#include "qgswidgetwrapper.h"
#include "qgis_gui.h"
#ifdef SIP_RUN
//%MappedType QList<QgsSearchWidgetWrapper::FilterFlag> /TypeHintIn = "Iterable[QgsSearchWidgetWrapper.FilterFlag]",TypeHintOut = "List[QgsSearchWidgetWrapper.FilterFlag]", TypeHintValue = "[]"/
{
//%TypeHeaderCode
#include <QList>
//%End
SIP_INSERT_QLIST_ENUM_CONVERSION_CODE( QgsSearchWidgetWrapper::FilterFlag, "" );
//%ConvertFromTypeCode
PyObject *l = PyList_New( sipCpp->size() );
if ( !l )
return 0;
for ( int i = 0; i < sipCpp->size(); ++i )
{
PyObject *eobj = sipConvertFromEnum( static_cast<int>( sipCpp->at( i ) ), sipType_QgsSearchWidgetWrapper_FilterFlag );
if ( !eobj )
{
Py_DECREF( l );
return 0;
}
PyList_SetItem( l, i, eobj );
}
return l;
//%End
//%ConvertToTypeCode
PyObject *iter = PyObject_GetIter( sipPy );
if ( !sipIsErr )
{
PyErr_Clear();
Py_XDECREF( iter );
return ( iter && !PyBytes_Check( sipPy ) && !PyUnicode_Check( sipPy ) );
}
if ( !iter )
{
*sipIsErr = 1;
return 0;
}
QList<QgsSearchWidgetWrapper::FilterFlag> *ql = new QList<QgsSearchWidgetWrapper::FilterFlag>;
for ( Py_ssize_t i = 0;; ++i )
{
PyErr_Clear();
PyObject *itm = PyIter_Next( iter );
if ( !itm )
{
if ( PyErr_Occurred() )
{
delete ql;
Py_DECREF( iter );
*sipIsErr = 1;
return 0;
}
break;
}
int v = sipConvertToEnum( itm, sipType_QgsSearchWidgetWrapper_FilterFlag );
if ( PyErr_Occurred() )
{
PyErr_Format( PyExc_TypeError, "index %zd has type '%s' but 'QgsSearchWidgetWrapper.FilterFlag' is expected", i, sipPyTypeName( Py_TYPE( itm ) ) );
Py_DECREF( itm );
delete ql;
Py_DECREF( iter );
*sipIsErr = 1;
return 0;
}
ql->append( static_cast<QgsSearchWidgetWrapper::FilterFlag>( v ) );
Py_DECREF( itm );
}
Py_DECREF( iter );
*sipCppPtr = ql;
return sipGetState( sipTransferObj );
//%End
};
#endif
/**
* \ingroup gui
*