# Buggy code
def __init__(self, name, *expressions, **kw):
    r"""Construct an index object.

    :param name:
      The name of the index

    :param \*expressions:
      Column expressions to include in the index.   The expressions
      are normally instances of :class:`.Column`, but may also
      be arbitrary SQL expressions which ultimately refer to a
      :class:`.Column`.

    :param unique=False:
        Keyword only argument; if True, create a unique index.

    :param quote=None:
        Keyword only argument; whether to apply quoting to the name of
        the index.  Works in the same manner as that of
        :paramref:`.Column.quote`.

    :param info=None: Optional data dictionary which will be populated
        into the :attr:`.SchemaItem.info` attribute of this object.

        .. versionadded:: 1.0.0

    :param \**kw: Additional keyword arguments not mentioned above are
        dialect specific, and passed in the form
        ``<dialectname>_<argname>``. See the documentation regarding an
        individual dialect at :ref:`dialect_toplevel` for detail on
        documented arguments.

    """
    self.table = table = None

    columns = []
    processed_expressions = []
    for (
        expr,
        column,
        strname,
        add_element,
    ) in self._extract_col_expression_collection(expressions):
        if add_element is not None:
            columns.append(add_element)
        processed_expressions.append(expr)

    self.expressions = processed_expressions
    self.name = quoted_name(name, kw.pop("quote", None))
    self.unique = kw.pop("unique", False)
    _column_flag = kw.pop("_column_flag", False)
    if "info" in kw:
        self.info = kw.pop("info")

    # TODO: consider "table" argument being public, but for
    # the purpose of the fix here, it starts as private.
    if "_table" in kw:
        table = kw.pop("_table")

    self._validate_dialect_kwargs(kw)

    # will call _set_parent() if table-bound column
    # objects are present
    ColumnCollectionMixin.__init__(self, *columns, _column_flag=_column_flag)

    if table is not None:
        self._set_parent(table)


# Traceback (AttributeError)
Traceback (most recent call last):
File "temp.py", line 24, in <module>
Base.metadata.create_all(engine)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/schema.py", line 4287, in create_all
ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 2036, in _run_visitor
conn._run_visitor(visitorcallable, element, **kwargs)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1607, in _run_visitor
visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/visitors.py", line 131, in traverse_single
return meth(obj, **kw)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/ddl.py", line 781, in visit_metadata
_is_metadata_operation=True,
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/visitors.py", line 131, in traverse_single
return meth(obj, **kw)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/ddl.py", line 833, in visit_table
self.traverse_single(index)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/visitors.py", line 131, in traverse_single
return meth(obj, **kw)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/ddl.py", line 862, in visit_index
self.connection.execute(CreateIndex(index))
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 988, in execute
return meth(self, multiparams, params)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/ddl.py", line 72, in _execute_on_connection
return connection._execute_ddl(self, multiparams, params)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1043, in _execute_ddl
else None,
File "<string>", line 1, in <lambda>
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 462, in compile
return self._compiler(dialect, bind=bind, **kw)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/ddl.py", line 29, in _compiler
return dialect.ddl_compiler(dialect, self, **kw)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/compiler.py", line 319, in __init__
self.string = self.process(self.statement, **compile_kwargs)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/compiler.py", line 350, in process
return obj._compiler_dispatch(self, **kwargs)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/sql/visitors.py", line 91, in _compiler_dispatch
return meth(self, **kw)
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/dialects/postgresql/base.py", line 1943, in visit_create_index
for expr in index.expressions
File "/home/jmabey/Code/bug/env/lib/python3.7/site-packages/sqlalchemy/dialects/postgresql/base.py", line 1943, in <listcomp>
for expr in index.expressions
AttributeError: 'NoneType' object has no attribute 'self_group'

# Fixed code
def __init__(self, name, *expressions, **kw):
    r"""Construct an index object.

    :param name:
      The name of the index

    :param \*expressions:
      Column expressions to include in the index.   The expressions
      are normally instances of :class:`.Column`, but may also
      be arbitrary SQL expressions which ultimately refer to a
      :class:`.Column`.

    :param unique=False:
        Keyword only argument; if True, create a unique index.

    :param quote=None:
        Keyword only argument; whether to apply quoting to the name of
        the index.  Works in the same manner as that of
        :paramref:`.Column.quote`.

    :param info=None: Optional data dictionary which will be populated
        into the :attr:`.SchemaItem.info` attribute of this object.

        .. versionadded:: 1.0.0

    :param \**kw: Additional keyword arguments not mentioned above are
        dialect specific, and passed in the form
        ``<dialectname>_<argname>``. See the documentation regarding an
        individual dialect at :ref:`dialect_toplevel` for detail on
        documented arguments.

    """
    self.table = table = None

    columns = []
    processed_expressions = []
    for (
        expr,
        column,
        strname,
        add_element,
    ) in self._extract_col_expression_collection(expressions):
        columns.append(add_element)
        processed_expressions.append(expr)

    self.expressions = processed_expressions
    self.name = quoted_name(name, kw.pop("quote", None))
    self.unique = kw.pop("unique", False)
    _column_flag = kw.pop("_column_flag", False)
    if "info" in kw:
        self.info = kw.pop("info")

    # TODO: consider "table" argument being public, but for
    # the purpose of the fix here, it starts as private.
    if "_table" in kw:
        table = kw.pop("_table")

    self._validate_dialect_kwargs(kw)

    # will call _set_parent() if table-bound column
    # objects are present
    ColumnCollectionMixin.__init__(self, *columns, _column_flag=_column_flag)

    if table is not None:
        self._set_parent(table)