-
Notifications
You must be signed in to change notification settings - Fork 12
20 - AttributeError: Can't pickle local object 'augment_visit.<locals>.augment_func' #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
3a4ea4e
20 - Replaced closure+function to keep state with classes implementin…
dineshtrivedi 17a6476
20 - Added pre-commit + fixing all black and isort issues
dineshtrivedi 39cdaee
20 - Removing unsed code
dineshtrivedi 4b87f8a
20 - Added all supported python versions under travis.yaml and change…
dineshtrivedi 40c5cbe
20 - Github Actions inspired (copied) from pylint project
dineshtrivedi 9aac81b
20 - Trying to trigger github actions
dineshtrivedi 8f2135c
20 - Removing pylint hook from ci
dineshtrivedi 992e972
20 - Added coveralls dedependency
dineshtrivedi cb85ee2
20 - Changed build badge to point to github actions and removed code …
dineshtrivedi f91e0e4
20 - Added black style badge
dineshtrivedi 17cbb58
20 - Removed travis.yml file
dineshtrivedi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,19 @@ | ||
[paths] | ||
source = | ||
pylint_plugin_utils | ||
|
||
[run] | ||
source=pylint_plugin_utils | ||
[report] | ||
include = | ||
pylint_plugin_utils/* | ||
omit = | ||
*/test/* | ||
exclude_lines = | ||
# Re-enable default pragma | ||
pragma: no cover | ||
|
||
# Debug-only code | ||
def __repr__ | ||
|
||
# Type checking code not executed during pytest runs | ||
if TYPE_CHECKING: | ||
@overload |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[flake8] | ||
ignore = | ||
E203, W503, # Incompatible with black see https://github.com/ambv/black/issues/315 | ||
|
||
max-line-length=88 | ||
max-complexity=39 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
repos: | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: v4.1.0 | ||
hooks: | ||
- id: trailing-whitespace | ||
- id: end-of-file-fixer | ||
- repo: https://github.com/PyCQA/isort | ||
rev: 5.10.1 | ||
hooks: | ||
- id: isort | ||
- repo: https://github.com/psf/black | ||
rev: 21.12b0 | ||
hooks: | ||
- id: black | ||
args: [--safe, --quiet] | ||
- repo: https://github.com/Pierre-Sassoulas/black-disable-checker/ | ||
rev: 1.0.1 | ||
hooks: | ||
- id: black-disable-checker | ||
- repo: https://github.com/PyCQA/flake8 | ||
rev: 4.0.1 | ||
hooks: | ||
- id: flake8 | ||
additional_dependencies: [flake8-typing-imports==1.10.1] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ python: | |
- "3.5" | ||
- "3.6" | ||
- "3.7" | ||
- "3.8" | ||
env: | ||
- PYLINT=2.0.0 | ||
- PYLINT=2.1.1 | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,75 @@ | ||
import sys | ||
from typing import List | ||
|
||
from pylint.exceptions import UnknownMessageError | ||
from pylint.lint import PyLinter | ||
|
||
|
||
def get_class(module_name, kls): | ||
parts = kls.split('.') | ||
parts = kls.split(".") | ||
m = __import__(module_name) | ||
for mp in module_name.split('.')[1:]: | ||
for mp in module_name.split(".")[1:]: | ||
m = getattr(m, mp) | ||
klass = getattr(m, parts[0]) | ||
return klass | ||
|
||
|
||
class NoSuchChecker(Exception): | ||
|
||
def __init__(self, checker_class): | ||
self.message = "Checker class %s was not found" % checker_class | ||
|
||
def __repr__(self): | ||
return self.message | ||
|
||
|
||
def get_checker(linter, checker_class): | ||
def get_checker(linter: PyLinter, checker_class): | ||
for checker in linter.get_checkers(): | ||
if isinstance(checker, checker_class): | ||
return checker | ||
raise NoSuchChecker(checker_class) | ||
|
||
|
||
def augment_visit(linter, checker_method, augmentation): | ||
def augment_visit(linter: PyLinter, checker_method, augmentation): | ||
""" | ||
Augmenting a visit enables additional errors to be raised (although that case is | ||
better served using a new checker) or to suppress all warnings in certain circumstances. | ||
better served using a new checker) or to suppress all warnings in certain | ||
circumstances. | ||
|
||
Augmenting functions should accept a 'chain' function, which runs the checker method | ||
and possibly any other augmentations, and secondly an Astroid node. "chain()" can be | ||
called at any point to trigger the continuation of other checks, or not at all to | ||
prevent any further checking. | ||
Augmenting functions should accept a 'chain' function, which runs the checker | ||
method and possibly any other augmentations, and secondly an Astroid node. | ||
"chain()" can be called at any point to trigger the continuation of other | ||
checks, or not at all to prevent any further checking. | ||
""" | ||
|
||
if sys.version_info[0] <= 2: | ||
checker = get_checker(linter, checker_method.im_class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good that this old v2 compatibility code is going :) |
||
else: | ||
try: | ||
checker = get_checker(linter, checker_method.__self__.__class__) | ||
except AttributeError: | ||
checker = get_checker(linter, get_class(checker_method.__module__, checker_method.__qualname__)) | ||
try: | ||
checker = get_checker(linter, checker_method.__self__.__class__) | ||
except AttributeError: | ||
checker = get_checker( | ||
linter, get_class(checker_method.__module__, checker_method.__qualname__) | ||
) | ||
|
||
old_method = getattr(checker, checker_method.__name__) | ||
setattr(checker, checker_method.__name__, AugmentFunc(old_method, augmentation)) | ||
|
||
|
||
class AugmentFunc: | ||
def __init__(self, old_method, augmentation_func): | ||
self.old_method = old_method | ||
self.augmentation_func = augmentation_func | ||
|
||
def augment_func(node): | ||
def chain(): | ||
old_method(node) | ||
augmentation(chain, node) | ||
def __call__(self, node): | ||
self.augmentation_func(Chain(self.old_method, node), node) | ||
|
||
setattr(checker, checker_method.__name__, augment_func) | ||
|
||
class Chain: | ||
def __init__(self, old_method, node): | ||
self.old_method = old_method | ||
self.node = node | ||
|
||
class Suppress(object): | ||
def __call__(self): | ||
self.old_method(self.node) | ||
|
||
|
||
class Suppress: | ||
def __init__(self, linter): | ||
self._linter = linter | ||
self._suppress = [] | ||
|
@@ -79,69 +90,79 @@ def suppress(self, *symbols): | |
def __exit__(self, exc_type, exc_val, exc_tb): | ||
self._linter.add_message = self._orig_add_message | ||
for to_append_args, to_append_kwargs in self._messages_to_append: | ||
# Depending on the Pylint version, the add_message API is different. | ||
# Either a single object called 'message' is passed, or the first argument | ||
# is a message symbol. | ||
if hasattr('symbol', to_append_args[0]): | ||
code = to_append_args[0].symbol | ||
else: | ||
code = to_append_args[0] | ||
if to_append_args[0] in self._suppress: | ||
continue | ||
self._linter.add_message(*to_append_args, **to_append_kwargs) | ||
|
||
|
||
def supress_message(linter, checker_method, message_id, test_func): | ||
import warnings | ||
warnings.warn("'supress_message' has been deprecated in favour of the correctly-spelled 'suppress_message'", | ||
DeprecationWarning) | ||
return suppress_message(linter, checker_method, message_id, test_func) | ||
|
||
|
||
def suppress_message(linter, checker_method, message_id_or_symbol, test_func): | ||
def suppress_message(linter: PyLinter, checker_method, message_id_or_symbol, test_func): | ||
""" | ||
This wrapper allows the suppression of a message if the supplied test function | ||
returns True. It is useful to prevent one particular message from being raised | ||
in one particular case, while leaving the rest of the messages intact. | ||
""" | ||
# At some point, pylint started preferring message symbols to message IDs. However this is not done | ||
# consistently or uniformly - occasionally there are some message IDs with no matching symbols. | ||
# We try to work around this here by suppressing both the ID and the symbol, if we can find it. | ||
# This also gives us compatability with a broader range of pylint versions. | ||
|
||
# Similarly, a commit between version 1.2 and 1.3 changed where the messages are stored - see: | ||
# https://bitbucket.org/logilab/pylint/commits/0b67f42799bed08aebb47babdc9fb0e761efc4ff#chg-reporters/__init__.py | ||
# Therefore here, we try the new attribute name, and fall back to the old version for | ||
# compatability with <=1.2 and >=1.3 | ||
msgs_store = getattr(linter, 'msgs_store', linter) | ||
|
||
def get_message_definitions(message_id_or_symbol): | ||
if hasattr(msgs_store, 'check_message_id'): | ||
augment_visit( | ||
linter, checker_method, DoSuppress(linter, message_id_or_symbol, test_func) | ||
) | ||
|
||
|
||
class DoSuppress: | ||
def __init__(self, linter: PyLinter, message_id_or_symbol, test_func): | ||
self.linter = linter | ||
self.message_id_or_symbol = message_id_or_symbol | ||
self.test_func = test_func | ||
|
||
def __call__(self, chain, node): | ||
with Suppress(self.linter) as s: | ||
if self.test_func(node): | ||
s.suppress(*self.symbols) | ||
chain() | ||
|
||
@property | ||
def symbols(self) -> List: | ||
# At some point, pylint started preferring message symbols to message IDs. | ||
# However, this is not done consistently or uniformly | ||
# - occasionally there are some message IDs with no matching symbols. | ||
# We try to work around this here by suppressing both the ID and the symbol. | ||
# This also gives us compatability with a broader range of pylint versions. | ||
|
||
# Similarly, between version 1.2 and 1.3 changed where the messages are stored | ||
# - see: | ||
# https://bitbucket.org/logilab/pylint/commits/0b67f42799bed08aebb47babdc9fb0e761efc4ff#chg-reporters/__init__.py | ||
# Therefore here, we try the new attribute name, and fall back to the old | ||
# version for compatability with <=1.2 and >=1.3 | ||
|
||
try: | ||
pylint_messages = self.get_message_definitions(self.message_id_or_symbol) | ||
the_symbols = [ | ||
symbol | ||
for pylint_message in pylint_messages | ||
for symbol in (pylint_message.msgid, pylint_message.symbol) | ||
if symbol is not None | ||
] | ||
except UnknownMessageError: | ||
# This can happen due to mismatches of pylint versions and plugin | ||
# expectations of available messages | ||
the_symbols = [self.message_id_or_symbol] | ||
|
||
return the_symbols | ||
|
||
def get_message_definitions(self, message_id_or_symbol): | ||
msgs_store = getattr(self.linter, "msgs_store", self.linter) | ||
|
||
if hasattr(msgs_store, "check_message_id"): | ||
return [msgs_store.check_message_id(message_id_or_symbol)] | ||
# pylint 2.0 renamed check_message_id to get_message_definition in: | ||
# https://github.com/PyCQA/pylint/commit/5ccbf9eaa54c0c302c9180bdfb745566c16e416d | ||
elif hasattr(msgs_store, 'get_message_definition'): | ||
elif hasattr(msgs_store, "get_message_definition"): | ||
return [msgs_store.get_message_definition(message_id_or_symbol)] | ||
# pylint 2.3.0 renamed get_message_definition to get_message_definitions in: | ||
# https://github.com/PyCQA/pylint/commit/da67a9da682e51844fbc674229ff6619eb9c816a | ||
elif hasattr(msgs_store, 'get_message_definitions'): | ||
elif hasattr(msgs_store, "get_message_definitions"): | ||
return msgs_store.get_message_definitions(message_id_or_symbol) | ||
else: | ||
raise ValueError('pylint.utils.MessagesStore does not have a get_message_definition(s) method') | ||
|
||
try: | ||
pylint_messages = get_message_definitions(message_id_or_symbol) | ||
symbols = [symbol | ||
for pylint_message in pylint_messages | ||
for symbol in (pylint_message.msgid, pylint_message.symbol) | ||
if symbol is not None] | ||
except UnknownMessageError: | ||
# This can happen due to mismatches of pylint versions and plugin expectations of available messages | ||
symbols = [message_id_or_symbol] | ||
|
||
def do_suppress(chain, node): | ||
with Suppress(linter) as s: | ||
if test_func(node): | ||
s.suppress(*symbols) | ||
chain() | ||
augment_visit(linter, checker_method, do_suppress) | ||
msg = ( | ||
"pylint.utils.MessagesStore does not have a " | ||
"get_message_definition(s) method" | ||
) | ||
raise ValueError(msg) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
-r requirements_test_pre_commit.txt | ||
-r requirements_test_min.txt | ||
pre-commit~=2.16 | ||
pytest-cov~=3.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-e . | ||
pytest~=6.2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Everything in this file should reflect the pre-commit configuration | ||
# in .pre-commit-config.yaml | ||
black==21.12b0 | ||
flake8==4.0.1 | ||
flake8-typing-imports==1.12.0 | ||
isort==5.10.1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[aliases] | ||
test = pytest | ||
|
||
[tool:pytest] | ||
testpaths = tests | ||
python_files = *test_*.py | ||
|
||
[isort] | ||
profile = black |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
setup.py
lists supported versions as 3.6 to 3.10 (which is good!) so the CI config should match.