jendrikseipp / vulture

Find dead Python code
MIT License
3.29k stars 145 forks source link

Feature request: A way to more specifically target items for whitelisting #343

Open Hubro opened 7 months ago

Hubro commented 7 months ago

I'm trying to implement Vulture for a big project at work that uses a proprietary application framework.

Entrypoints into the application are classes with a specific name (Main) that are subclasses of a specific framework class (acme_corp.application.Service) placed in a very specifically named module (e.g. my_package_name/main.py). The framework also has hooks, which are defined as methods with very specific names in subclasses of a specific framework class.

This is a very large codebase, and simply whitelisting the names Main, _.before, _.after etc. is likely to hit much more than just the entrypoints that I want to whitelist.

It would be tremendously useful if Vulture leveraged the AST to allow even more specific whitelists. You could take into account the type of object (if it's a constant, variable, class, method, function etc.), the location (file name, module name, package name), the base classes and so on.

To maintain backwards compatability, this could be added as a new feature, for example:

pyproject.toml:

[tool.vulture]

paths = "packages/"

entrypoints = [
    # Any class named "Main" in a module whose name ends with ".main" that is a
    # subclass of "acme_corp.application.Application"
    {
        type = "class",
        name = "Main",
        base_classes = ["acme_corp.application.Application"],
        module_name = "/\\.main$/",
    },

    # Any method named "create", "pre_hook" or "post_hook" in a class like the
    # one above
    {
        type = "method",
        name = ["create", "pre_hook", "post_hook"],
        parent_class = {
            name = "Main",
            base_classes = ["acme_corp.application.Application"],
            module_name = "/\\.main$/",
        }
    },

    # Any method named "pre_hook" or "post_hook" in a subclass of
    # "acme_corp.application.Service". (The class itself is *not* whitelisted.)
    {
        type = "method",
        name = ["pre_hook", "post_hook"],
        parent_class = {
            base_classes = ["acme_corp.application.Service"],
        }
    },

    # Class attributes named "name_prefix" in subclasses of
    # "acme_corp.application.Service". (The class itself is *not* whitelisted.)
    {
        type = "class_attribute",
        name = "name_prefix",
        parent_class = {
            base_classes = ["acme_corp.application.Service"],
        }
    },
]

Alternative names: mark_used, tag, (?)

Amvoled commented 7 months ago

I've started using vulture a few days ago and I've run into the same problem. Sometimes we just implement new features incrementally and therefore leave sections of code unused for a few commits. What I've done so far is name these functions projectnamefuture_... and filtered them using --ignore-names. I've then added a # TODO: ... comment on them as this leaves a warning in another tool we use. I think it could be a good idea to add a flag --ignore-with-todo that would not report function / variables that have a # TODO: ... comment directly above them for these situations specifically. I can try to implement something if you like the idea.