Skip to content
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

Swap plugin cache to pickle-able values when done #7640

Merged
merged 9 commits into from
Oct 20, 2022
Merged

Swap plugin cache to pickle-able values when done #7640

merged 9 commits into from
Oct 20, 2022

Conversation

daogilvie
Copy link
Contributor

Type of Changes

Type
🐛 Bug fix

Description

When the dictionary has served its purpose (making plugin loading pre-and-post init a consistent behaviour), we swap it for bools indicating whether or not a module was loaded.
We don't currently use the bools, but it seemed a sensible choice. The main idea is to make the dictionary fully pickle-able, so that when dill pickles the linter for multiprocessing, it doesn't crash horribly.

Closes #7635

When the dictionary has served its purpose (making plugin loading
pre-and-post init a consistent behaviour), we swap it for bools
indicating whether or not a module was loaded.
We don't currently use the bools, but it seemed a sensible choice.
The main idea is to make the dictionary fully pickle-able, so that when
dill pickles the linter for multiprocessing, it doesn't crash horribly.
@coveralls
Copy link

coveralls commented Oct 17, 2022

Pull Request Test Coverage Report for Build 3288211080

  • 3 of 3 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.0003%) to 95.349%

Totals Coverage Status
Change from base Build 3284966210: 0.0003%
Covered Lines: 17138
Relevant Lines: 17974

💛 - Coveralls

@github-actions

This comment has been minimized.

Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix @daogilvie! Verified that it does resolve the issue. Left a small comment. Besides that the fix is fine IMO. Will leave the actual approval for someone with more experience with multitasking in pylint.

pylint/lint/pylinter.py Outdated Show resolved Hide resolved
@cdce8p cdce8p added Crash 💥 A bug that makes pylint crash multiprocessing macOS labels Oct 17, 2022
@cdce8p cdce8p added this to the 2.15.5 milestone Oct 17, 2022
Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daogilvie Have you considered adding a test for this?

doc/whatsnew/fragments/7635.bugfix Outdated Show resolved Hide resolved
pylint/lint/pylinter.py Outdated Show resolved Hide resolved
@daogilvie
Copy link
Contributor Author

@daogilvie Have you considered adding a test for this?

I honestly did not, no, because I wasn't sure how to do that beyond what the existing tests are doing in test_check_parallel. I'll look into it this evening; I'm sure there will be a way!

@DanielNoord
Copy link
Collaborator

I honestly did not, no, because I wasn't sure how to do that beyond what the existing tests are doing in test_check_parallel. I'll look into it this evening; I'm sure there will be a way!

Yeah, I think just linting with j=2 and a plugin over an empty file might already be enough. Just something to make sure we don't regress on this.
This seems like something that we can easily forget about during a larger refactoring of the multiprocessing code.

This should cover the case where plugins are loaded and parallel running
is enabled.
@daogilvie
Copy link
Contributor Author

I honestly did not, no, because I wasn't sure how to do that beyond what the existing tests are doing in test_check_parallel. I'll look into it this evening; I'm sure there will be a way!

Yeah, I think just linting with j=2 and a plugin over an empty file might already be enough. Just something to make sure we don't regress on this. This seems like something that we can easily forget about during a larger refactoring of the multiprocessing code.

It looks like the reason existing parallel tests didn't catch this is that they directly register the checkers on the linter, so they bypass the plugin loading code completely.

I have added a test that doesn't actually lint a file — it just loads the dummy plugin into a linter object and verifies the linter can then be pickled. In addition to not doubling-up the content of other tests, the only time this test would need re-working is if parallel running was revamped so heavily as not to relying on pickling, I think — does it sound like something that will suit?

@github-actions

This comment has been minimized.

@Pierre-Sassoulas Pierre-Sassoulas added the Needs backport Needs to be cherry-picked on the current patch version by a pylint's maintainer label Oct 17, 2022
DanielNoord
DanielNoord previously approved these changes Oct 17, 2022
pylint/lint/pylinter.py Outdated Show resolved Hide resolved
tests/test_check_parallel.py Outdated Show resolved Hide resolved
Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test case doesn't seem to work as expected. It still passes when I revert the fix. From the looks of it, the plugin is never loaded - at least liinter._dynamic_plugins is empty.

tests/test_check_parallel.py Outdated Show resolved Hide resolved
The test also includes an assert to confirm the module picked is
actually unsafe, in case it is made safe in the future.
Also include docstring edits suggested by reviews.
@daogilvie
Copy link
Contributor Author

I've modified the test to use a non-pickle-safe module explicitly, and to verify the module cannot be pickled (in case it is made pickle-safe in the future independently).
I've also included suggested changes to docstrings and comments, and I've tripled-checked my pre-commit setup and test accuracy 😂

@daogilvie
Copy link
Contributor Author

daogilvie commented Oct 18, 2022

Ok I am genuinely mortified and confused, sorry, I seem to have caused another failure in parallel tests. Working on it. There are two pre-existing failures in the test_functional file also, I assume they are known.

EDIT: Oh, it seems that the set of default plugins loaded is different depending on whether you run the full test suite or just the pickle test in isolation, and catching the error that happens with the specific plugin I chose is actually not enough when the extras are loaded. Addressing now.

@github-actions

This comment has been minimized.

Running in isolation and as part of the full suite cause different
default plugins to be loaded, which throw different pickling errors.
This will now catch all of them, and still fail the test if all of those
modules become pickle safe in future.
@daogilvie daogilvie removed the request for review from DanielNoord October 18, 2022 08:44
@daogilvie daogilvie requested a review from cdce8p October 18, 2022 08:44
@github-actions
Copy link
Contributor

🤖 Effect of this PR on checked open source code: 🤖

Effect on pandas:
The following messages are no longer emitted:

  1. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/series/indexing/test_delitem.py#L72
  2. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/frame/test_constructors.py#L903
  3. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/frame/test_constructors.py#L904
  4. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/frame/test_constructors.py#L908
  5. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/frame/test_constructors.py#L909
  6. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/frame/test_constructors.py#L2674
  7. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/frame/methods/test_combine_first.py#L343
  8. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/dtypes/test_dtypes.py#L272
  9. no-member:
    Instance of 'DatetimeIndex' has no 'round' member
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/arrays/test_datetimelike.py#L653
  10. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/period/test_constructors.py#L211
  11. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/period/test_constructors.py#L216
  12. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/period/test_constructors.py#L225
  13. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/period/test_constructors.py#L229
  14. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L79
  15. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L86
  16. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L90
  17. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L94
  18. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L98
  19. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L102
  20. redefined-variable-type:
    Redefinition of exp type from pandas.core.indexes.base.Index to pandas.core.indexes.numeric.NumericIndex
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L270
  21. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L304
  22. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L308
  23. redefined-variable-type:
    Redefinition of expected type from pandas.core.indexes.base.Index to pandas.core.indexes.numeric.NumericIndex
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L467
  24. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L486
  25. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L554
  26. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L558
  27. redefined-variable-type:
    Redefinition of idx type from pandas.core.indexes.numeric.UInt64Index to pandas.core.indexes.base.Index
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L619
  28. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L640
  29. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexes/numeric/test_numeric.py#L644
  30. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/tests/indexing/test_coercion.py#L342
  31. no-member:
    Method 'dtype' has no '_resolution_obj' member
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/core/indexes/period.py#L172
  32. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/core/indexes/period.py#L407
  33. comparison-with-callable:
    Comparing against a callable, did you omit the parenthesis?
    https://github.com/pandas-dev/pandas/blob/4583a045e7123032dbf7856429ef411713a6937b/pandas/core/indexes/period.py#L455

Effect on psycopg:
The following messages are now emitted:

  1. no-member:
    Instance of 'ByteaLoader' has no '_escaping' member
    https://github.com/psycopg/psycopg/blob/d7a3785804ac97e139355e52bded734a13b62f26/psycopg/psycopg/types/string.py#L151

This comment was generated for commit 695fc14

Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't test locally but this seems to make sense!

I'll let somebody else test and approve this! Thanks for all your work on this!

pylint/lint/pylinter.py Show resolved Hide resolved
tests/test_check_parallel.py Outdated Show resolved Hide resolved
tests/test_check_parallel.py Outdated Show resolved Hide resolved
cdce8p
cdce8p previously approved these changes Oct 20, 2022
Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work @daogilvie 🚀

@daogilvie
Copy link
Contributor Author

daogilvie commented Oct 20, 2022

Oh, huh, actually do you mind if I put myself in the script/.contributors_aliases.json file before merge? I didn't bother last time as it felt a bit presumptuous but I feel like two issues closed (even if I did cause the second one) means I probably should 😂

@cdce8p
Copy link
Member

cdce8p commented Oct 20, 2022

Oh, huh, actually do you mind if I put myself in the script/.contributors_aliases.json file before merge? I didn't bother last time as it felt a bit presumptuous but I feel like two issues closed (even if I did cause the second one) means I probably should 😂

I believe Pierre added you already.
https://github.com/PyCQA/pylint/blob/e8ba3eb002b533e6640d6eeb25a66bab04602951/script/.contributors_aliases.json#L439-L442

@daogilvie
Copy link
Contributor Author

daogilvie commented Oct 20, 2022

Oh, huh, actually do you mind if I put myself in the script/.contributors_aliases.json file before merge? I didn't bother last time as it felt a bit presumptuous but I feel like two issues closed (even if I did cause the second one) means I probably should 😂

I believe Pierre added you already.

https://github.com/PyCQA/pylint/blob/e8ba3eb002b533e6640d6eeb25a66bab04602951/script/.contributors_aliases.json#L439-L442

Oh that's great! Thank you again @Pierre-Sassoulas for covering for my laziness 👀 — I might just shorten my name though if that's ok 😄

@cdce8p
Copy link
Member

cdce8p commented Oct 20, 2022

Oh that's great! Thank you again @Pierre-Sassoulas for covering for my laziness 👀 — I might just shorten my name though if that's ok 😄

Please do if you like!

@cdce8p cdce8p merged commit 015f340 into pylint-dev:main Oct 20, 2022
@daogilvie daogilvie deleted the 7635-thread-safe-plugin-check branch October 20, 2022 10:07
cdce8p added a commit to cdce8p/pylint that referenced this pull request Oct 20, 2022
When the dictionary has served its purpose (making plugin loading
pre-and-post init a consistent behaviour), we swap it for bools
indicating whether or not a module was loaded.
We don't currently use the bools, but it seemed a sensible choice.
The main idea is to make the dictionary fully pickle-able, so that when
dill pickles the linter for multiprocessing, it doesn't crash horribly.

Co-authored-by: Daniël van Noord <[email protected]>
Co-authored-by: Marc Mueller <[email protected]>
@cdce8p cdce8p added Backported and removed Needs backport Needs to be cherry-picked on the current patch version by a pylint's maintainer labels Oct 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash with -j 2 when linting empty file
5 participants