diff --git a/AUTHORS b/AUTHORS index 614d8918..54c8a48f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,6 +16,7 @@ Alphabetical list of contributors: * ali-tny * andrew deryabin * Andrew Tipton +* Anshul Singh * atronah * casey * CauĂȘ Beloni diff --git a/CHANGELOG b/CHANGELOG index 44d5938e..7077c896 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ Development Version ------------------- -Nothing yet. +* Fix IndexError in ``strip_whitespace`` for parenthesis groups that + collapse to a single nested child (e.g. ``( AS )``). See issue885. Release 0.6.0 (Aug 13, 2026) diff --git a/sqlparse/filters/others.py b/sqlparse/filters/others.py index 95bc436c..528c69f6 100644 --- a/sqlparse/filters/others.py +++ b/sqlparse/filters/others.py @@ -112,13 +112,18 @@ def _stripws_identifierlist(self, tlist): return self._stripws_default(tlist) def _stripws_parenthesis(self, tlist): + # Well-formed groups look like "(", content..., ")". Some inputs + # (e.g. "( AS )") collapse to a single nested child, so there is + # no tokens[1] / tokens[-2] to strip. + if len(tlist.tokens) < 3: + return self._stripws_default(tlist) while tlist.tokens[1].is_whitespace: tlist.tokens.pop(1) while tlist.tokens[-2].is_whitespace: tlist.tokens.pop(-2) if tlist.tokens[-2].is_group: # save to remove the last whitespace - while tlist.tokens[-2].tokens[-1].is_whitespace: + while tlist.tokens[-2].tokens and tlist.tokens[-2].tokens[-1].is_whitespace: tlist.tokens[-2].tokens.pop(-1) self._stripws_default(tlist) diff --git a/tests/test_regressions.py b/tests/test_regressions.py index aca7f7b3..38333426 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -285,6 +285,12 @@ def test_issue213_leadingws(): assert sqlparse.format(sql, strip_whitespace=True) == "select * from foo" +def test_issue885_strip_ws_malformed_parenthesis(): + # Parenthesis grouping can collapse "( AS )" to a single nested child. + # strip_whitespace must not assume tokens[1] / tokens[-2] exist. + assert sqlparse.format("( AS )", strip_whitespace=True) == "( AS )" + + def test_issue227_gettype_cte(): select_stmt = sqlparse.parse('SELECT 1, 2, 3 FROM foo;') assert select_stmt[0].get_type() == 'SELECT'