# Buggy code
def apply_fixes(self, fixes):
    """Apply an iterable of fixes to this segment.

    Used in applying fixes if we're fixing linting errors.
    If anything changes, this should return a new version of the segment
    rather than mutating the original.

    Note: We need to have fixes to apply AND this must have children. In the case
    of raw segments, they will be replaced or removed by their parent and
    so this function should just return self.
    """
    # Let's check what we've been given.
    if fixes and isinstance(fixes[0], SQLLintError):
        logging.error("Transforming `fixes` from errors into a list of fixes")
        # We've got linting errors, let's aggregate them into a list of fixes
        buff = []
        for err in fixes:
            buff += err.fixes
        # Overwrite fixes
        fixes = buff

    if fixes and not self.is_raw():
        # Get a reference to self to start with, but this will rapidly
        # become a working copy.
        r = self

        # Make a working copy
        seg_buffer = []
        todo_buffer = list(self.segments)
        while True:
            if len(todo_buffer) == 0:
                break
            else:
                seg = todo_buffer.pop(0)
                unused_fixes = []
                for f in fixes:
                    if f.anchor == seg:
                        if f.edit_type == "delete":
                            # We're just getting rid of this segment.
                            seg = None
                        elif f.edit_type in ("edit", "create"):
                            # We're doing a replacement (it could be a single segment or an iterable)
                            if isinstance(f.edit, BaseSegment):
                                seg_buffer.append(f.edit)
                            else:
                                for s in f.edit:
                                    seg_buffer.append(s)

                            if f.edit_type == "create":
                                # in the case of a creation, also add this segment on the end
                                seg_buffer.append(seg)
                        else:
                            raise ValueError(
                                "Unexpected edit_type: {0!r} in {1!r}".format(
                                    f.edit_type, f
                                )
                            )
                        # We've applied a fix here. Move on, this also consumes the fix
                        # TODO: Maybe deal with overlapping fixes later.
                        break
                    else:
                        # We've not used the fix so we should keep it in the list for later.
                        unused_fixes.append(f)
                else:
                    seg_buffer.append(seg)
            # Switch over the the unused list
            fixes = unused_fixes

        # Then recurse (i.e. deal with the children) (Requeueing)
        seg_queue = seg_buffer
        seg_buffer = []
        for seg in seg_queue:
            s, fixes = seg.apply_fixes(fixes)
            seg_buffer.append(s)

        # Reform into a new segment
        r = r.__class__(segments=tuple(seg_buffer), pos_marker=r.pos_marker)

        # Lastly, before returning, we should realign positions.
        # Note: Realign also returns a copy
        return r.realign(), fixes
    else:
        return self, fixes


# Traceback (TypeError)
$ sqlfluff fix --rules L001 forecastservice\sql\get_phasing_v2.sql
==== finding violations ====
== [forecastservice\sql\get_phasing_v2.sql] FAIL
L:   0 | P:   0 | ???? | Failure in Jinja templating: 'first_mon' is undefined. Have you configured your variables?
L:   7 | P:   1 | ???? | Unable to lex characters: ''{% if regi'...'
==== fixing violations ====
2 violations found
Are you sure you wish to attempt to fix these? [Y/n] ...
Attempting fixes...
Persisting Changes...
Traceback (most recent call last):
File "C:\Users\alan\dev\tails-analytics-forecastservice\env\Scripts\sqlfluff-script.py", line 11, in <module>
load_entry_point('sqlfluff==0.2.4', 'console_scripts', 'sqlfluff')()
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 764, in __call__
return self.main(*args, **kwargs)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 717, in main
rv = self.invoke(ctx)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 555, in invoke
return callback(*args, **kwargs)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\cli\commands.py", line 197, in fix
result.persist_changes(verbosity=verbose)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 327, in persist_changes
return self.combine_dicts(*[path.persist_changes(verbosity=verbosity) for path in self.paths])
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 327, in <listcomp>
return self.combine_dicts(*[path.persist_changes(verbosity=verbosity) for path in self.paths])
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 253, in persist_changes
return {file.path: file.persist_tree(verbosity=verbosity) for file in self.files}
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 253, in <dictcomp>
return {file.path: file.persist_tree(verbosity=verbosity) for file in self.files}
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 61, in persist_tree
diff_templ_codes = diff_templ.get_opcodes()
File "C:\Users\alan\AppData\Local\Programs\Python\Python36\lib\difflib.py", line 550, in get_opcodes
for ai, bj, size in self.get_matching_blocks():
File "C:\Users\alan\AppData\Local\Programs\Python\Python36\lib\difflib.py", line 467, in get_matching_blocks
la, lb = len(self.a), len(self.b)
TypeError: object of type 'NoneType' has no len()

# Fixed code
def apply_fixes(self, fixes):
    """Apply an iterable of fixes to this segment.

    Used in applying fixes if we're fixing linting errors.
    If anything changes, this should return a new version of the segment
    rather than mutating the original.

    Note: We need to have fixes to apply AND this must have children. In the case
    of raw segments, they will be replaced or removed by their parent and
    so this function should just return self.
    """
    # Let's check what we've been given.
    if fixes and isinstance(fixes[0], SQLLintError):
        logging.error("Transforming `fixes` from errors into a list of fixes")
        # We've got linting errors, let's aggregate them into a list of fixes
        buff = []
        for err in fixes:
            buff += err.fixes
        # Overwrite fixes
        fixes = buff

    if fixes and not self.is_raw():
        # Get a reference to self to start with, but this will rapidly
        # become a working copy.
        r = self

        # Make a working copy
        seg_buffer = []
        todo_buffer = list(self.segments)
        while True:
            if len(todo_buffer) == 0:
                break
            else:
                seg = todo_buffer.pop(0)
                # We don't apply fixes to meta segments
                if seg.is_meta:
                    seg_buffer.append(seg)
                    continue

                fix_buff = fixes.copy()
                unused_fixes = []
                while fix_buff:
                    f = fix_buff.pop()
                    if f.anchor == seg:
                        if f.edit_type == "delete":
                            # We're just getting rid of this segment.
                            seg = None
                        elif f.edit_type in ("edit", "create"):
                            # We're doing a replacement (it could be a single segment or an iterable)
                            if isinstance(f.edit, BaseSegment):
                                seg_buffer.append(f.edit)
                            else:
                                for s in f.edit:
                                    seg_buffer.append(s)

                            if f.edit_type == "create":
                                # in the case of a creation, also add this segment on the end
                                seg_buffer.append(seg)
                        else:
                            raise ValueError(
                                "Unexpected edit_type: {0!r} in {1!r}".format(
                                    f.edit_type, f
                                )
                            )
                        # We've applied a fix here. Move on, this also consumes the fix
                        # TODO: Maybe deal with overlapping fixes later.
                        break
                    else:
                        # We've not used the fix so we should keep it in the list for later.
                        unused_fixes.append(f)
                else:
                    seg_buffer.append(seg)
            # Switch over the the unused list
            fixes = unused_fixes + fix_buff

        # Then recurse (i.e. deal with the children) (Requeueing)
        seg_queue = seg_buffer
        seg_buffer = []
        for seg in seg_queue:
            s, fixes = seg.apply_fixes(fixes)
            seg_buffer.append(s)

        # Reform into a new segment
        r = r.__class__(
            segments=tuple(seg_buffer), pos_marker=r.pos_marker, validate=False
        )

        # Lastly, before returning, we should realign positions.
        # Note: Realign also returns a copy
        return r.realign(), fixes
    else:
        return self, fixes