-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Initial implementation of pylintd #5401
base: main
Are you sure you want to change the base?
Conversation
Of course this PR is not finished. It is more as Proof of concept. |
Pull Request Test Coverage Report for Build 1505341505
π - Coveralls |
pylint-dev/astroid#792 might be a problem if we want to be able to have an efficient |
I agree but using separate service can enable users for some workarounds like restarting pylintd service on regular basis. (I know not ideal...) |
@Pierre-Sassoulas our experience with running pylint as a daemon suggests that leaks definitely will be a problem. Given that any leaking node retains the full AST, so memory consumption get uncomfortably high very quickly when linting large files. |
I have a question. How we can proceed with this PR (except unittests and fixing the failed CI)? I am willing to continue with this PR but I would like to understand what is missing in order to finalise this PR. I would like to keep it as simple as possible right now maybe it can be added as experimental feature. Afterwards I can create additional issues/PRs with further improvements of |
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.
To be fair I don't know how that would be used or how it would affect pylint's user. I'm not using blackd myself so I don't really know what to expect and how to use a pylint deamon. If needs some automated tests for sure, maybe discussion with potential users ?
It's probably aimed toward those with a big codebase that launch analysis on single file often ? Might be useful for pre-commit too as pre-commit launch multiple pylint in parallel so if we use pylintd we skip the startup time ? Does the pre-commit use case makes sense to you @matusvalo ?
if not args: | ||
print(linter.help()) | ||
sys.exit(32) | ||
|
||
def initialize_jobs(self, linter: PyLinter) -> None: |
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.
I like the function created here π
if __name__ == "__main__": | ||
try: | ||
DaemonRun(sys.argv, 8000) | ||
except KeyboardInterrupt: | ||
pass |
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.
if __name__ == "__main__": | |
try: | |
DaemonRun(sys.argv, 8000) | |
except KeyboardInterrupt: | |
pass |
I guess it's for manual tests ?
I mentioned it in the issue already. I think we should not move forward with it, at this time. Maybe at some point we can pick it up again. #4814 (comment)
If the startup time isn't too slow, most users (read IDEs, ...) will simply choose the easiest path which is likely launching it direct. They have that implemented already for other tools, no need to change it. Tbh aside from a few outliers I haven't seen a use case for it yet.
For pre-commit it would be much better to use pylints own multiprocessing. |
I agree just partially . Calling pylintd using curl with empty cache gives ~24% speedup - 0m5.146s vs 0m3.920s which I consider significant - see my test above. Regarding usage of pylintd, editors can spawn pylintd and use it's HTTP API instead of calling pylint command. On the other hand, I think we need also input from developers of editors/plugins whether it make sense or they would use such API. |
Seems like the potential user are plugin editor then. A 25% perf gain is huge imo. But we'll have to handle caching properly in astroid or it won't last long though. I think we could move this MR to 3.0 alpha version and communicate with pylint-pycharm and vscode about it in order to see what they need and how it should be implemented. Do you want to lead the communication and specification effort @matusvalo ? |
for more information, see https://pre-commit.ci
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Yes, I can take this activity on my shoulders. But unfortunately, I was playing more with the implementation and I found out that the leak is pretty serious (~1 GB allocated memory after 10 runs of linting the same file). Moreover it seems that even the performance decreases over time :-/. I suppose, we need to progress with pylint-dev/astroid#792 in order to have functional pylintd. Btw. just side not around the usability of the pylintd - I just came across that blackd has already some plugins [1]. This is kind of usage of pylintd I imagine. |
Not sure it's a good idea to start the conversation now. It's not yet clear if or when we can fix astroid. It also isn't a priority at the moment, IMO rightly so. There are other areas that need attention first. If you never the less want to start the conversation, please make it clear that this is only experimental (at the moment) and still a long way of (maybe even years). |
I agree. I have mentioned it in previous message. At least memory leak should be solved first. |
Hey @matusvalo just mentioning it might be worth it to get a new benchmark on memory usage after pylint-dev/astroid#1521. If you use |
@jacobtylerwalls unfortunately even after the fix (testing on main), there is a leak - consider following example: from pylint.lint import Run
from pylint.lint import pylinter
while True:
Run(["pylint/checkers/variables.py"], exit=False)
pylinter.MANAGER.clear_cache() Following script after ~1 minute allocates around 1 GB of memory and keep raising: Moreover, it removes the performance benefit of avoiding rescanning cached files again and again - hence it yields no or zero perf. improvement. |
What if you explicitly call garbage collection? |
The memory leaks in pylint-dev/astroid#792 have been solved (except for some very small ones, perhaps), but because it relies on clearing the cache to do so, that kind of violates the spirit of this PR, which is to keep the cache. We probably want something like caching the astroid trees for third-party modules to disk, or having another separate cache for them. We could do that by checking if the third-party module defines a version constant. |
Do we know how |
Type of Changes
Description
This PR introduces basic implementation of
pylintd
- pylint deamon running in the background. It is similar implementation asmypyd
[1] orblackd
[2]. The implementation is highly inspired byblackd
approach.pylintd
is implemented as simple http server providing simple API for passing files for linting and returning back the result.The speedup of mainly gained in following areas:
pylint
initialization overhead.pylintd
.Examples:
Following examples shows comparison between running
pylint
andpylintd
against 2 large files inpylint
. The test was executed as follows:pylintd
was executedpylint
command was executed against the filepylintd
was asked to lint the filepylintd
was asked again to lint the file without restartingpylintd
(this shows speedup when astroid manager cache is filled)[1] https://mypy.readthedocs.io/en/stable/mypy_daemon.html
[2] https://black.readthedocs.io/en/stable/usage_and_configuration/black_as_a_server.html
This PR can partially help closing #4814