# Buggy code
def extract_from_part(parsed, stop_at_punctuation=True):
    tbl_prefix_seen = False
    for item in parsed.tokens:
        if tbl_prefix_seen:
            if is_subselect(item):
                for x in extract_from_part(item, stop_at_punctuation):
                    yield x
            elif stop_at_punctuation and item.ttype is Punctuation:
                raise StopIteration
            # An incomplete nested select won't be recognized correctly as a
            # sub-select. eg: 'SELECT * FROM (SELECT id FROM user'. This causes
            # the second FROM to trigger this elif condition resulting in a
            # StopIteration. So we need to ignore the keyword if the keyword
            # FROM.
            # Also 'SELECT * FROM abc JOIN def' will trigger this elif
            # condition. So we need to ignore the keyword JOIN and its variants
            # INNER JOIN, FULL OUTER JOIN, etc.
            elif (
                item.ttype is Keyword
                and (not item.value.upper() == "FROM")
                and (not item.value.upper().endswith("JOIN"))
            ):
                raise StopIteration
            else:
                yield item
        elif (
            item.ttype is Keyword or item.ttype is Keyword.DML
        ) and item.value.upper() in (
            "COPY",
            "FROM",
            "INTO",
            "UPDATE",
            "TABLE",
            "JOIN",
        ):
            tbl_prefix_seen = True
        # 'SELECT a, FROM abc' will detect FROM as part of the column list.
        # So this check here is necessary.
        elif isinstance(item, IdentifierList):
            for identifier in item.get_identifiers():
                if identifier.ttype is Keyword and identifier.value.upper() == "FROM":
                    tbl_prefix_seen = True
                    break


# Traceback (RuntimeError)
Traceback (most recent call last):
File "c:\python37\lib\site-packages\mycli\packages\parseutils.py", line 95, in extract_from_part
raise StopIteration
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):w to complete suggestion
File "c:\python37\lib\threading.py", line 917, in _bootstrap_inner
self.run()
File "c:\python37\lib\threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "c:\python37\lib\site-packages\prompt_toolkit\interface.py", line 865, in run
completions = list(buffer.completer.get_completions(document, complete_event))
File "c:\python37\lib\site-packages\mycli\sqlcompleter.py", line 258, in get_completions
suggestions = suggest_type(document.text, document.text_before_cursor)
File "c:\python37\lib\site-packages\mycli\packages\completion_engine.py", line 93, in suggest_type
full_text, identifier)
File "c:\python37\lib\site-packages\mycli\packages\completion_engine.py", line 203, in suggest_based_on_last_token
return [{'type': 'column', 'tables': extract_tables(full_text)}]
File "c:\python37\lib\site-packages\mycli\packages\parseutils.py", line 154, in extract_tables
return list(extract_table_identifiers(stream))
File "c:\python37\lib\site-packages\mycli\packages\parseutils.py", line 113, in extract_table_identifiers
for item in token_stream:
RuntimeError: generator raised StopIteration

# Fixed code
def extract_from_part(parsed, stop_at_punctuation=True):
    tbl_prefix_seen = False
    for item in parsed.tokens:
        if tbl_prefix_seen:
            if is_subselect(item):
                for x in extract_from_part(item, stop_at_punctuation):
                    yield x
            elif stop_at_punctuation and item.ttype is Punctuation:
                return
            # An incomplete nested select won't be recognized correctly as a
            # sub-select. eg: 'SELECT * FROM (SELECT id FROM user'. This causes
            # the second FROM to trigger this elif condition resulting in a
            # StopIteration. So we need to ignore the keyword if the keyword
            # FROM.
            # Also 'SELECT * FROM abc JOIN def' will trigger this elif
            # condition. So we need to ignore the keyword JOIN and its variants
            # INNER JOIN, FULL OUTER JOIN, etc.
            elif (
                item.ttype is Keyword
                and (not item.value.upper() == "FROM")
                and (not item.value.upper().endswith("JOIN"))
            ):
                return
            else:
                yield item
        elif (
            item.ttype is Keyword or item.ttype is Keyword.DML
        ) and item.value.upper() in (
            "COPY",
            "FROM",
            "INTO",
            "UPDATE",
            "TABLE",
            "JOIN",
        ):
            tbl_prefix_seen = True
        # 'SELECT a, FROM abc' will detect FROM as part of the column list.
        # So this check here is necessary.
        elif isinstance(item, IdentifierList):
            for identifier in item.get_identifiers():
                if identifier.ttype is Keyword and identifier.value.upper() == "FROM":
                    tbl_prefix_seen = True
                    break