Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion pyflakes/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import contextlib
import doctest
import functools
import importlib
import os
import re
import string
Expand Down Expand Up @@ -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:
Expand All @@ -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.
Expand Down
Empty file added pyflakes/plugins/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions pyflakes/plugins/leo_plugin.py
Original file line number Diff line number Diff line change
@@ -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
Loading