Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Raise IndexErrors instead of crashing when an invalid index is
passed to QgsAttributeTableConfig methods from Python
  • Loading branch information
nyalldawson authored and github-actions[bot] committed Aug 11, 2021
1 parent ddc4815 commit 7e57b54
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 0 deletions.
74 changes: 74 additions & 0 deletions python/core/auto_generated/qgsattributetableconfig.sip.in
Expand Up @@ -64,6 +64,20 @@ The list order defines the order of appearance.
bool isEmpty() const;
%Docstring
Returns ``True`` if the configuration is empty, ie it contains no columns.

.. seealso:: :py:func:`size`
%End

int size() const;
%Docstring
Returns the number of columns in the configuration.

.. versionadded:: 3.22
%End

int __len__() const;
%MethodCode
sipRes = sipCpp->size();
%End

int mapVisibleColumnToIndex( int visibleColumn ) const;
Expand Down Expand Up @@ -129,14 +143,31 @@ Gets the expression used for sorting.
Set the sort expression used for sorting.
%End


int columnWidth( int column ) const;
%Docstring
Returns the width of a column, or -1 if column should use default width.

:param column: column index

:raises IndexError: if the column is not found

.. seealso:: :py:func:`setColumnWidth`
%End
%MethodCode
{
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
return PyLong_FromLong( sipCpp->columnWidth( a0 ) );
}
}
%End


void setColumnWidth( int column, int width );
%Docstring
Expand All @@ -145,17 +176,47 @@ Sets the width of a column.
:param column: column index
:param width: column width in pixels, or -1 if column should use default width

:raises IndexError: if the column is not found

.. seealso:: :py:func:`columnWidth`
%End
%MethodCode
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
sipCpp->setColumnWidth( a0, a1 );
}
%End


bool columnHidden( int column ) const;
%Docstring
Returns ``True`` if the specified column is hidden.

:param column: column index

:raises IndexError: if the column is not found

.. seealso:: :py:func:`setColumnHidden`
%End
%MethodCode
{
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
return PyBool_FromLong( sipCpp->columnHidden( a0 ) );
}
}
%End


void setColumnHidden( int column, bool hidden );
%Docstring
Expand All @@ -164,7 +225,20 @@ Sets whether the specified column should be hidden.
:param column: column index
:param hidden: set to ``True`` to hide column

:raises IndexError: if the column is not found

.. seealso:: :py:func:`columnHidden`
%End
%MethodCode
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
sipCpp->setColumnHidden( a0, a1 );
}
%End

Qt::SortOrder sortOrder() const;
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsattributetableconfig.cpp
Expand Up @@ -27,6 +27,11 @@ bool QgsAttributeTableConfig::isEmpty() const
return mColumns.isEmpty();
}

int QgsAttributeTableConfig::size() const
{
return mColumns.size();
}

int QgsAttributeTableConfig::mapVisibleColumnToIndex( int visibleColumn ) const
{
for ( int i = 0; i < mColumns.size(); ++i )
Expand Down
114 changes: 114 additions & 0 deletions src/core/qgsattributetableconfig.h
Expand Up @@ -84,9 +84,25 @@ class CORE_EXPORT QgsAttributeTableConfig

/**
* Returns TRUE if the configuration is empty, ie it contains no columns.
*
* \see size()
*/
bool isEmpty() const;

/**
* Returns the number of columns in the configuration.
*
* \since QGIS 3.22
*/
int size() const;

#ifdef SIP_RUN
int __len__() const;
% MethodCode
sipRes = sipCpp->size();
% End
#endif

/**
* Maps a visible column index to its original column index.
* \param visibleColumn index of visible column
Expand Down Expand Up @@ -148,27 +164,103 @@ class CORE_EXPORT QgsAttributeTableConfig
*/
void setSortExpression( const QString &sortExpression );

#ifndef SIP_RUN

/**
* Returns the width of a column, or -1 if column should use default width.
* \param column column index
* \see setColumnWidth()
*/
int columnWidth( int column ) const;
#else

/**
* Returns the width of a column, or -1 if column should use default width.
* \param column column index
* \throws IndexError if the column is not found
* \see setColumnWidth()
*/
int columnWidth( int column ) const;
% MethodCode
{
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
return PyLong_FromLong( sipCpp->columnWidth( a0 ) );
}
}
% End
#endif

#ifndef SIP_RUN

/**
* Sets the width of a column.
* \param column column index
* \param width column width in pixels, or -1 if column should use default width
* \see columnWidth()
*/
void setColumnWidth( int column, int width );
#else

/**
* Sets the width of a column.
* \param column column index
* \param width column width in pixels, or -1 if column should use default width
* \throws IndexError if the column is not found
* \see columnWidth()
*/
void setColumnWidth( int column, int width );
% MethodCode
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
sipCpp->setColumnWidth( a0, a1 );
}
% End
#endif

#ifndef SIP_RUN

/**
* Returns TRUE if the specified column is hidden.
* \param column column index
* \see setColumnHidden()
*/
bool columnHidden( int column ) const;
#else

/**
* Returns TRUE if the specified column is hidden.
* \param column column index
* \throws IndexError if the column is not found
* \see setColumnHidden()
*/
bool columnHidden( int column ) const;
% MethodCode
{
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
return PyBool_FromLong( sipCpp->columnHidden( a0 ) );
}
}
% End
#endif

#ifndef SIP_RUN

/**
* Sets whether the specified column should be hidden.
Expand All @@ -177,6 +269,28 @@ class CORE_EXPORT QgsAttributeTableConfig
* \see columnHidden()
*/
void setColumnHidden( int column, bool hidden );
#else

/**
* Sets whether the specified column should be hidden.
* \param column column index
* \param hidden set to TRUE to hide column
* \throws IndexError if the column is not found
* \see columnHidden()
*/
void setColumnHidden( int column, bool hidden );
% MethodCode
if ( a0 < 0 || a0 >= sipCpp->size() )
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
else
{
sipCpp->setColumnHidden( a0, a1 );
}
% End
#endif

/**
* Gets the sort order
Expand Down
67 changes: 67 additions & 0 deletions tests/src/python/test_qgsattributetableconfig.py
Expand Up @@ -53,6 +53,21 @@ def testIsEmpty(self):
config.setColumns([c])
self.assertFalse(config.isEmpty())

def testSize(self):
"""
Test QgsAttributeTableConfig.size and __len__
"""
config = QgsAttributeTableConfig()
self.assertEqual(config.size(), 0)
self.assertEqual(len(config), 0)

c1 = QgsAttributeTableConfig.ColumnConfig()
c2 = QgsAttributeTableConfig.ColumnConfig()
config.setColumns([c1, c2])

self.assertEqual(config.size(), 2)
self.assertEqual(len(config), 2)

def testSetColumns(self):
""" test setting columns """
config = QgsAttributeTableConfig()
Expand Down Expand Up @@ -90,6 +105,11 @@ def testColumnHidden(self):
self.assertFalse(config.columnHidden(0))
self.assertFalse(config.columnHidden(1))

with self.assertRaises(IndexError):
config.columnHidden(-1)
with self.assertRaises(IndexError):
config.columnHidden(2)

config.setColumnHidden(1, True)
self.assertFalse(config.columnHidden(0))
self.assertTrue(config.columnHidden(1))
Expand All @@ -102,11 +122,58 @@ def testColumnHidden(self):
self.assertTrue(config.columns()[0].hidden)
self.assertTrue(config.columns()[1].hidden)

with self.assertRaises(IndexError):
config.setColumnHidden(-1, True)
with self.assertRaises(IndexError):
config.setColumnHidden(2, True)

c2.hidden = True
config.setColumns([c1, c2])
self.assertFalse(config.columnHidden(0))
self.assertTrue(config.columnHidden(1))

def testColumnWidth(self):
""" test setting column widths """

config = QgsAttributeTableConfig()
c1 = QgsAttributeTableConfig.ColumnConfig()
c1.name = 'test'
c1.width = -1
c2 = QgsAttributeTableConfig.ColumnConfig()
c2.name = 'test2'
c2.width = 27
config.setColumns([c1, c2])

self.assertEqual(config.columnWidth(0), -1)
self.assertEqual(config.columnWidth(1), 27)

with self.assertRaises(IndexError):
config.columnWidth(-1)
with self.assertRaises(IndexError):
config.columnWidth(2)

config.setColumnWidth(1, -1)
self.assertEqual(config.columnWidth(0), -1)
self.assertEqual(config.columnWidth(1), -1)
self.assertEqual(config.columns()[0].width, -1)
self.assertEqual(config.columns()[1].width, -1)

config.setColumnWidth(0, 34)
self.assertEqual(config.columnWidth(0), 34)
self.assertEqual(config.columnWidth(1), -1)
self.assertEqual(config.columns()[0].width, 34)
self.assertEqual(config.columns()[1].width, -1)

with self.assertRaises(IndexError):
config.setColumnWidth(-1, 11)
with self.assertRaises(IndexError):
config.setColumnWidth(2, 11)

c2.width = 12
config.setColumns([c1, c2])
self.assertEqual(config.columnWidth(0), -1)
self.assertEqual(config.columnWidth(1), 12)

def testSameColumns(self):
""" test hasSameColumns() check """

Expand Down

0 comments on commit 7e57b54

Please sign in to comment.