flake8-plugin-utils icon indicating copy to clipboard operation
flake8-plugin-utils copied to clipboard

How to get the `filename` in the `Visitor`?

Open Kludex opened this issue 4 years ago • 2 comments

  • Date you used flake8-plugin-utils: 24/07/2021
  • flake8-plugin-utils version used, if any: 1.3.2
  • Python version, if any: 3.8
  • Operating System: Ubuntu 20.04

Description

I'm trying to build a plugin, on which I need to know what is the variable I'm looking at. For example:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def home():
    return "Hello world!"

How can I be sure that the decorator app is that FastAPI object? What if I have multiple modules, how can I be sure which FastAPI object I'm using for the decorator?

I thought about mapping the object with the filename, so I can check the imports on the files and be sure what the object actually is.

Well, the question basically is: how can I get the filename in the Visitor?

FWIW, I'm building this package.

Thank you very much for the package! :)

Kludex avatar Jul 24 '21 18:07 Kludex

I've found out. I need to ask flake8 for that field: https://github.com/Kludex/flake8-fastapi/pull/13/files

The thing is that, there are others fields that I may need: https://flake8.pycqa.org/en/latest/plugin-development/plugin-parameters.html#indicating-desired-data

My workaround works fine, but we probably want to have a native setup, so we don't need to override the run method?

EDIT: The solution above doesn't work on the tests, just on the plugin itself. :cry:

Kludex avatar Jul 24 '21 19:07 Kludex

I would be interested in this being supported by default as well. My current workaround is to use patched versions of both the Plugin and Visitor classes:

import os

from flake8_plugin_utils import Plugin as _Plugin, Visitor as _Visitor


class Plugin(_Plugin):
    def __init__(self, tree, filename, *args, **kwargs):
        super(Plugin, self).__init__(tree)
        self.filename = filename

    def run(self):
        for visitor_cls in self.visitors:
            visitor = self._create_visitor(visitor_cls, filename=self.filename)
            visitor.visit(self._tree)

            for error in visitor.errors:
                yield self._error(error)
    
    @classmethod
    def _create_visitor(cls, visitor_cls, filename=None):
        if cls.config is None:
            return visitor_cls(filename=filename)

        return visitor_cls(config=cls.config, filename=filename)


class Visitor(_Visitor):
    def __init__(self, config=None, filename=None) -> None:
        super(Visitor, self).__init__(config=config)
        if not os.path.isabs(filename):
            filename = os.path.realpath(filename)
        self.filename = filename

stefan6419846 avatar Jul 14 '22 08:07 stefan6419846