threading_checker.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  2. # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
  3. # Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt
  4. from __future__ import annotations
  5. from typing import TYPE_CHECKING
  6. from astroid import nodes
  7. from pylint.checkers import BaseChecker
  8. from pylint.checkers.utils import only_required_for_messages, safe_infer
  9. if TYPE_CHECKING:
  10. from pylint.lint import PyLinter
  11. class ThreadingChecker(BaseChecker):
  12. """Checks for threading module.
  13. - useless with lock - locking used in wrong way that has no effect (with threading.Lock():)
  14. """
  15. name = "threading"
  16. LOCKS = frozenset(
  17. (
  18. "threading.Lock",
  19. "threading.RLock",
  20. "threading.Condition",
  21. "threading.Semaphore",
  22. "threading.BoundedSemaphore",
  23. )
  24. )
  25. msgs = {
  26. "W2101": (
  27. "'%s()' directly created in 'with' has no effect",
  28. "useless-with-lock",
  29. "Used when a new lock instance is created by using with statement "
  30. "which has no effect. Instead, an existing instance should be used to acquire lock.",
  31. ),
  32. }
  33. @only_required_for_messages("useless-with-lock")
  34. def visit_with(self, node: nodes.With) -> None:
  35. context_managers = (c for c, _ in node.items if isinstance(c, nodes.Call))
  36. for context_manager in context_managers:
  37. if isinstance(context_manager, nodes.Call):
  38. infered_function = safe_infer(context_manager.func)
  39. if infered_function is None:
  40. continue
  41. qname = infered_function.qname()
  42. if qname in self.LOCKS:
  43. self.add_message("useless-with-lock", node=node, args=qname)
  44. def register(linter: PyLinter) -> None:
  45. linter.register_checker(ThreadingChecker(linter))