# Buggy code
def attr_class_maker_callback(
    ctx: "mypy.plugin.ClassDefContext", auto_attribs_default: bool = False
) -> None:
    """Add necessary dunder methods to classes decorated with attr.s.

    attrs is a package that lets you define classes without writing dull boilerplate code.

    At a quick glance, the decorator searches the class body for assignments of `attr.ib`s (or
    annotated variables if auto_attribs=True), then depending on how the decorator is called,
    it will add an __init__ or all the __cmp__ methods.  For frozen=True it will turn the attrs
    into properties.

    See http://www.attrs.org/en/stable/how-does-it-work.html for information on how attrs works.
    """
    info = ctx.cls.info

    init = _get_decorator_bool_argument(ctx, "init", True)
    frozen = _get_frozen(ctx)
    cmp = _get_decorator_bool_argument(ctx, "cmp", True)
    auto_attribs = _get_decorator_bool_argument(
        ctx, "auto_attribs", auto_attribs_default
    )
    kw_only = _get_decorator_bool_argument(ctx, "kw_only", False)

    if ctx.api.options.python_version[0] < 3:
        if auto_attribs:
            ctx.api.fail("auto_attribs is not supported in Python 2", ctx.reason)
            return
        if not info.defn.base_type_exprs:
            # Note: This will not catch subclassing old-style classes.
            ctx.api.fail("attrs only works with new-style classes", info.defn)
            return
        if kw_only:
            ctx.api.fail(KW_ONLY_PYTHON_2_UNSUPPORTED, ctx.reason)
            return

    attributes = _analyze_class(ctx, auto_attribs, kw_only)

    if ctx.api.options.new_semantic_analyzer:
        # Check if attribute types are ready.
        for attr in attributes:
            if info[attr.name].type is None and not ctx.api.final_iteration:
                ctx.api.defer()
                return

    # Save the attributes so that subclasses can reuse them.
    ctx.cls.info.metadata["attrs"] = {
        "attributes": [attr.serialize() for attr in attributes],
        "frozen": frozen,
    }

    adder = MethodAdder(ctx)
    if init:
        _add_init(ctx, attributes, adder)
    if cmp:
        _add_cmp(ctx, adder)
    if frozen:
        _make_frozen(ctx, attributes)


# Traceback (KeyError)
/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/aiohttp/client.py:49: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.rtfd.io/en/latest/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.720+dev.262fe3dc4d5d14492c6fd4009d91c555c406ac04
Traceback (most recent call last):
File "/Users/skreft/.virtualenvs/zapship/bin/mypy", line 10, in <module>
sys.exit(console_entry())
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/__main__.py", line 8, in console_entry
main(None, sys.stdout, sys.stderr)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/main.py", line 83, in main
res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/build.py", line 164, in build
result = _build(sources, options, alt_lib_path, flush_errors, fscache, stdout, stderr)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/build.py", line 224, in _build
graph = dispatch(sources, manager, stdout)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/build.py", line 2567, in dispatch
process_graph(graph, manager)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/build.py", line 2880, in process_graph
process_stale_scc(graph, scc, manager)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/build.py", line 2978, in process_stale_scc
semantic_analysis_for_scc(graph, scc, manager.errors)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal_main.py", line 74, in semantic_analysis_for_scc
process_top_levels(graph, scc, patches)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal_main.py", line 193, in process_top_levels
patches)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal_main.py", line 315, in semantic_analyze_target
active_type=active_type)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal.py", line 360, in refresh_partial
self.refresh_top_level(node)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal.py", line 371, in refresh_top_level
self.accept(d)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal.py", line 4435, in accept
node.accept(self)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/nodes.py", line 923, in accept
return visitor.visit_class_def(self)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal.py", line 978, in visit_class_def
self.analyze_class(defn)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal.py", line 1049, in analyze_class
self.analyze_class_body_common(defn)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal.py", line 1058, in analyze_class_body_common
self.apply_class_plugin_hooks(defn)
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/newsemanal/semanal.py", line 1103, in apply_class_plugin_hooks
hook(ClassDefContext(defn, decorator, self))
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/plugins/attrs.py", line 214, in attr_class_maker_callback
if info[attr.name].type is None and not ctx.api.final_iteration:
File "/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/mypy/nodes.py", line 2413, in __getitem__
raise KeyError(name)
KeyError: 'total'
/Users/skreft/.virtualenvs/zapship/lib/python3.6/site-packages/aiohttp/client.py:49: : note: use --pdb to drop into pdb

# Fixed code
def attr_class_maker_callback(
    ctx: "mypy.plugin.ClassDefContext", auto_attribs_default: bool = False
) -> None:
    """Add necessary dunder methods to classes decorated with attr.s.

    attrs is a package that lets you define classes without writing dull boilerplate code.

    At a quick glance, the decorator searches the class body for assignments of `attr.ib`s (or
    annotated variables if auto_attribs=True), then depending on how the decorator is called,
    it will add an __init__ or all the __cmp__ methods.  For frozen=True it will turn the attrs
    into properties.

    See http://www.attrs.org/en/stable/how-does-it-work.html for information on how attrs works.
    """
    info = ctx.cls.info

    init = _get_decorator_bool_argument(ctx, "init", True)
    frozen = _get_frozen(ctx)
    cmp = _get_decorator_bool_argument(ctx, "cmp", True)
    auto_attribs = _get_decorator_bool_argument(
        ctx, "auto_attribs", auto_attribs_default
    )
    kw_only = _get_decorator_bool_argument(ctx, "kw_only", False)

    if ctx.api.options.python_version[0] < 3:
        if auto_attribs:
            ctx.api.fail("auto_attribs is not supported in Python 2", ctx.reason)
            return
        if not info.defn.base_type_exprs:
            # Note: This will not catch subclassing old-style classes.
            ctx.api.fail("attrs only works with new-style classes", info.defn)
            return
        if kw_only:
            ctx.api.fail(KW_ONLY_PYTHON_2_UNSUPPORTED, ctx.reason)
            return

    attributes = _analyze_class(ctx, auto_attribs, kw_only)

    if ctx.api.options.new_semantic_analyzer:
        # Check if attribute types are ready.
        for attr in attributes:
            node = info.get(attr.name)
            if node is None:
                # This name is likely blocked by a star import. We don't need to defer because
                # defer() is already called by mark_incomplete().
                return
            if node.type is None and not ctx.api.final_iteration:
                ctx.api.defer()
                return

    # Save the attributes so that subclasses can reuse them.
    ctx.cls.info.metadata["attrs"] = {
        "attributes": [attr.serialize() for attr in attributes],
        "frozen": frozen,
    }

    adder = MethodAdder(ctx)
    if init:
        _add_init(ctx, attributes, adder)
    if cmp:
        _add_cmp(ctx, adder)
    if frozen:
        _make_frozen(ctx, attributes)