Skip to content

Commit 4735402

Browse files
committed
Add plugins folder. Add Checker.load_plugins and call it
1 parent 59ec459 commit 4735402

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

pyflakes/checker.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import contextlib
1212
import doctest
1313
import functools
14+
import importlib
1415
import os
1516
import re
1617
import string
@@ -744,8 +745,10 @@ def __init__(self, tree, filename='(none)', builtins=None,
744745
self.withDoctest = withDoctest
745746
self.exceptHandlers = [()]
746747
self.root = tree
747-
748748
self.scopeStack = []
749+
750+
self.load_plugins()
751+
749752
try:
750753
scope_tp = Checker._ast_node_scope[type(tree)]
751754
except KeyError:
@@ -765,6 +768,29 @@ def __init__(self, tree, filename='(none)', builtins=None,
765768
stacklevel=2,
766769
)
767770

771+
def load_plugins(self) -> None:
772+
"""Load all plugins"""
773+
plugins_directory = os.path.normpath(os.path.join(os.path.dirname(
774+
__file__), 'plugins'))
775+
if not os.path.exists(plugins_directory):
776+
return
777+
for filename in os.listdir(plugins_directory):
778+
if filename.startswith('_'):
779+
continue
780+
path = os.path.join(plugins_directory, filename)
781+
base, extension = os.path.splitext(filename)
782+
if extension != '.py' :
783+
continue
784+
try:
785+
module_name = f"plugins.{base}"
786+
plugin = importlib.import_module(module_name)
787+
importlib.reload(plugin)
788+
# print(f"Loaded plugin: {module_name}")
789+
if hasattr(plugin, "register"):
790+
plugin.register(self)
791+
except Exception as e:
792+
print(f"Can not import {module_name}: {e}")
793+
768794
def deferFunction(self, callable):
769795
"""
770796
Schedule a function handler to be called just before completion.

pyflakes/plugins/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# pyflakes/plugins/__init__.py

pyflakes/plugins/leo_plugin.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#@+leo-ver=5-thin
2+
#@+node:ekr.20251125174431.1: * @file plugins/leo_plugin.py
3+
"""A plugin for pyflakes that improves testing of ast.ATTRIBUTE nodes."""
4+
5+
import ast
6+
import os
7+
8+
#@+others
9+
#@+node:ekr.20251126064813.1: ** leo_plugin: funcToMethod
10+
def funcToMethod(f: Callable, theClass: object, name: str = None) -> None:
11+
"""
12+
From the Python Cookbook...
13+
14+
The following method allows you to add a function as a method of
15+
any class. That is, it converts the function to a method of the
16+
class. The method just added is available instantly to all
17+
existing instances of the class, and to all instances created in
18+
the future.
19+
20+
The function's first argument should be self.
21+
22+
The newly created method has the same name as the function unless
23+
the optional name argument is supplied, in which case that name is
24+
used as the method name.
25+
"""
26+
setattr(theClass, name or f.__name__, f)
27+
28+
#@+node:ekr.20251126060205.1: ** leo_plugin: patched_ATTRIBUTE
29+
def patched_ATTRIBUTE(self, node) -> None:
30+
if isinstance(node.ctx, ast.Load):
31+
if isinstance(node.value, ast.Name):
32+
if 1: ### Don't put this in production code!
33+
print(f"patched_ATTRIBUTE: load {node.value.id}.{node.attr}")
34+
self.handleChildren(node)
35+
#@+node:ekr.20251126054330.1: ** leo_plugin: register
36+
def register(pyflakes) -> None:
37+
"""Register the leo_plugin plugin."""
38+
if 0:
39+
path, extension = os.path.splitext(__file__)
40+
print(f"V6: {os.path.basename(path)}.register: pyflakes: {pyflakes!r}")
41+
42+
# Patch pyflakes.ATTRIBUTE.
43+
funcToMethod(patched_ATTRIBUTE, pyflakes.__class__, 'ATTRIBUTE')
44+
#@-others
45+
#@-leo

0 commit comments

Comments
 (0)