From 47354022ad95550a0f2e64e5ddae3e3a26dd6e4e Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 26 Nov 2025 12:01:33 -0600 Subject: [PATCH 1/2] Add plugins folder. Add Checker.load_plugins and call it --- pyflakes/checker.py | 28 ++++++++++++++++++++- pyflakes/plugins/__init__.py | 1 + pyflakes/plugins/leo_plugin.py | 45 ++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 pyflakes/plugins/__init__.py create mode 100644 pyflakes/plugins/leo_plugin.py diff --git a/pyflakes/checker.py b/pyflakes/checker.py index 629dacf0..7dc28158 100644 --- a/pyflakes/checker.py +++ b/pyflakes/checker.py @@ -11,6 +11,7 @@ import contextlib import doctest import functools +import importlib import os import re import string @@ -744,8 +745,10 @@ def __init__(self, tree, filename='(none)', builtins=None, self.withDoctest = withDoctest self.exceptHandlers = [()] self.root = tree - self.scopeStack = [] + + self.load_plugins() + try: scope_tp = Checker._ast_node_scope[type(tree)] except KeyError: @@ -765,6 +768,29 @@ def __init__(self, tree, filename='(none)', builtins=None, stacklevel=2, ) + def load_plugins(self) -> None: + """Load all plugins""" + plugins_directory = os.path.normpath(os.path.join(os.path.dirname( + __file__), 'plugins')) + if not os.path.exists(plugins_directory): + return + for filename in os.listdir(plugins_directory): + if filename.startswith('_'): + continue + path = os.path.join(plugins_directory, filename) + base, extension = os.path.splitext(filename) + if extension != '.py' : + continue + try: + module_name = f"plugins.{base}" + plugin = importlib.import_module(module_name) + importlib.reload(plugin) + # print(f"Loaded plugin: {module_name}") + if hasattr(plugin, "register"): + plugin.register(self) + except Exception as e: + print(f"Can not import {module_name}: {e}") + def deferFunction(self, callable): """ Schedule a function handler to be called just before completion. diff --git a/pyflakes/plugins/__init__.py b/pyflakes/plugins/__init__.py new file mode 100644 index 00000000..7e04e6ac --- /dev/null +++ b/pyflakes/plugins/__init__.py @@ -0,0 +1 @@ +# pyflakes/plugins/__init__.py \ No newline at end of file diff --git a/pyflakes/plugins/leo_plugin.py b/pyflakes/plugins/leo_plugin.py new file mode 100644 index 00000000..0c45e486 --- /dev/null +++ b/pyflakes/plugins/leo_plugin.py @@ -0,0 +1,45 @@ +#@+leo-ver=5-thin +#@+node:ekr.20251125174431.1: * @file plugins/leo_plugin.py +"""A plugin for pyflakes that improves testing of ast.ATTRIBUTE nodes.""" + +import ast +import os + +#@+others +#@+node:ekr.20251126064813.1: ** leo_plugin: funcToMethod +def funcToMethod(f: Callable, theClass: object, name: str = None) -> None: + """ + From the Python Cookbook... + + The following method allows you to add a function as a method of + any class. That is, it converts the function to a method of the + class. The method just added is available instantly to all + existing instances of the class, and to all instances created in + the future. + + The function's first argument should be self. + + The newly created method has the same name as the function unless + the optional name argument is supplied, in which case that name is + used as the method name. + """ + setattr(theClass, name or f.__name__, f) + +#@+node:ekr.20251126060205.1: ** leo_plugin: patched_ATTRIBUTE +def patched_ATTRIBUTE(self, node) -> None: + if isinstance(node.ctx, ast.Load): + if isinstance(node.value, ast.Name): + if 1: ### Don't put this in production code! + print(f"patched_ATTRIBUTE: load {node.value.id}.{node.attr}") + self.handleChildren(node) +#@+node:ekr.20251126054330.1: ** leo_plugin: register +def register(pyflakes) -> None: + """Register the leo_plugin plugin.""" + if 0: + path, extension = os.path.splitext(__file__) + print(f"V6: {os.path.basename(path)}.register: pyflakes: {pyflakes!r}") + + # Patch pyflakes.ATTRIBUTE. + funcToMethod(patched_ATTRIBUTE, pyflakes.__class__, 'ATTRIBUTE') +#@-others +#@-leo From e5f046bc4bdaa1a0813ec816dabfdc93742f70c5 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 26 Nov 2025 12:10:04 -0600 Subject: [PATCH 2/2] Remove comment --- pyflakes/plugins/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyflakes/plugins/__init__.py b/pyflakes/plugins/__init__.py index 7e04e6ac..e69de29b 100644 --- a/pyflakes/plugins/__init__.py +++ b/pyflakes/plugins/__init__.py @@ -1 +0,0 @@ -# pyflakes/plugins/__init__.py \ No newline at end of file