# Buggy code
def _filter_names(
    names: Iterable,
    label: str,
    include: Optional[Iterable],
    exclude: Optional[Iterable],
):
    if include and exclude:
        intersection = set(include) & set(exclude)
        if intersection:
            values = ", ".join(intersection)
            raise InvalidArgumentError(
                f"'{values}' specified in both --include-{label} and --exclude-{label}"
            )

    names = [tuple(name.split(".")) for name in names]

    def _filter(filters, update_func):
        filters = [tuple(name.split(".")) for name in filters]
        for length, groups in groupby(filters, len):
            for group in groups:
                matches = [name for name in names if name[:length] == group]
                if not matches:
                    name = ".".join(group)
                    raise InvalidArgumentError(
                        f"'{name}' does not match any known {label}"
                    )
                update_func({match: None for match in matches})

    if include:
        ret: OrderedDict = OrderedDict()
        _filter(include, ret.update)
    else:
        ret = OrderedDict({name: None for name in names})

    if exclude:
        _filter(exclude, ret.difference_update)  # type: ignore[attr-defined]

    return [".".join(name) for name in ret]


# Traceback (AttributeError)
dvc exp show --exclude-metrics train -v
2020-11-22 14:31:39,852 DEBUG: Check for update is enabled.
2020-11-22 14:31:39,880 DEBUG: fetched: [(3,)]
2020-11-22 14:31:41,553 DEBUG: fetched: [(12331,)]
2020-11-22 14:31:42,627 ERROR: unexpected error - 'collections.OrderedDict' object has no attribute 'difference_update'
------------------------------------------------------------
Traceback (most recent call last):
File "/home/saugat/repos/iterative/dvc/dvc/main.py", line 90, in main
ret = cmd.run()
File "/home/saugat/repos/iterative/dvc/dvc/command/experiments.py", line 335, in run
_show_experiments(
File "/home/saugat/repos/iterative/dvc/dvc/command/experiments.py", line 265, in _show_experiments
metric_names, param_names = _collect_names(
File "/home/saugat/repos/iterative/dvc/dvc/command/experiments.py", line 84, in _collect_names
metric_names = _filter_names(
File "/home/saugat/repos/iterative/dvc/dvc/command/experiments.py", line 61, in _filter_names
_filter(exclude, ret.difference_update)
AttributeError: 'collections.OrderedDict' object has no attribute 'difference_update'
------------------------------------------------------------

# Fixed code
def _filter_names(
    names: Iterable,
    label: str,
    include: Optional[Iterable],
    exclude: Optional[Iterable],
):
    if include and exclude:
        intersection = set(include) & set(exclude)
        if intersection:
            values = ", ".join(intersection)
            raise InvalidArgumentError(
                f"'{values}' specified in both --include-{label} and --exclude-{label}"
            )

    names = [tuple(name.split(".")) for name in names]

    def _filter(filters, update_func):
        filters = [tuple(name.split(".")) for name in filters]
        for length, groups in groupby(filters, len):
            for group in groups:
                matches = [name for name in names if name[:length] == group]
                if not matches:
                    name = ".".join(group)
                    raise InvalidArgumentError(
                        f"'{name}' does not match any known {label}"
                    )
                update_func({match: None for match in matches})

    if include:
        ret: OrderedDict = OrderedDict()
        _filter(include, ret.update)
    else:
        ret = OrderedDict({name: None for name in names})

    if exclude:
        to_remove = {}
        _filter(exclude, to_remove.update)
        for key in to_remove:
            if key in ret:
                del ret[key]

    return [".".join(name) for name in ret]