Skip to content

repo: inline filter_file(..., **kwargs)#3423

Open
haampie wants to merge 1 commit intodevelopfrom
hs/typing/filter_file
Open

repo: inline filter_file(..., **kwargs)#3423
haampie wants to merge 1 commit intodevelopfrom
hs/typing/filter_file

Conversation

@haampie
Copy link
Member

@haampie haampie commented Feb 14, 2026

Type checkers have issue with kwargs = {...} + f(**kwargs) due to type
erasure. The pattern is often somewhat redundant and seems to have been
copied to match style of other packages.

  • Inline **kwargs
  • Remove kwargs that repeat defaults

Before: 1762 diagnostics, after: 1525 diagnostics; from ty check --extra-search-path ~/spack/lib/spack --extra-search-path repos --ignore unresolved-reference --output-format concise

was done automatically
#!/usr/bin/env python3

import ast
import sys

filter_file_defaults = {
    "string":False,
    "backup":False,
    "ignore_absent":False,
    "start_at":None,
    "stop_at":None,
    "encoding":"utf-8",
}



def check_filter_file_calls(filename):
    with open(filename, "r") as f:
        lines = f.readlines()

    tree = ast.parse("".join(lines), filename=filename)

    for node in ast.walk(tree):
        # find the last assignment to `kwargs` in the current scope
        if isinstance(node, ast.Assign) and isinstance(node.value, ast.Dict):
            for target in node.targets:
                if isinstance(target, ast.Name) and target.id == "kwargs":
                    kwargs_value = {}
                    for key, value in zip(node.value.keys, node.value.values):
                        if isinstance(key, ast.Constant):
                            kwargs_value[key.value] = ast.literal_eval(value)
                    print(f"{filename}:{node.lineno}:{node.col_offset}:{node.end_col_offset}: kwargs = {kwargs_value}")
                    # remove all defaults from kwargs_value
                    for k in filter_file_defaults:
                        if k in kwargs_value and kwargs_value[k] == filter_file_defaults[k]:
                            del kwargs_value[k]

        # either the funcion call is `filter_file(..., **kwargs)`
        # or its obj.filter(..., **kwargs)

        if not isinstance(node, ast.Call):
            continue
        
        if (
            getattr(node.func, "id", None) == "filter_file"
            or isinstance(node.func, ast.Attribute) and node.func.attr == "filter"
        ):
            if node.keywords:
                for kw in node.keywords:
                    if isinstance(kw.value, ast.Name) and kw.value.id == "kwargs":
                        if not kwargs_value:
                            # kwargs is empty, we delete this part from the function call
                            lines[kw.lineno - 1] = lines[kw.lineno - 1][:kw.col_offset] + lines[kw.lineno - 1][kw.end_col_offset:]
                        else:
                            # we inline the kwargs values directly into the function call
                            lines[kw.lineno - 1] = lines[kw.lineno - 1][:kw.col_offset] + ", ".join(f"{k}={repr(v)}" for k, v in kwargs_value.items()) + lines[kw.lineno - 1][kw.end_col_offset:]
                        print(lines[kw.lineno - 1], end="")

    with open(filename, "w") as f:
        f.writelines(lines)

            

if __name__ == "__main__":
    for filename in sys.argv[1:]:
        check_filter_file_calls(filename)

Type checkers have issue with `kwargs = {...}`, `f(**kwargs)` due to
type erasure, but the pattern is often not needed and probably just
copied over from existing packages.

* Inline `**kwargs`
* Remove kwargs that repeat defaults

Signed-off-by: Harmen Stoppels <harmenstoppels@gmail.com>
Copy link
Contributor

@climbfuji climbfuji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mainly looked at eccodes. Thanks for cleaning this up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants