__init__.py 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. """Custom module loader."""
  2. from __future__ import annotations
  3. from argparse import ArgumentParser
  4. from importlib import import_module
  5. from pathlib import Path
  6. from pkgutil import walk_packages
  7. from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type
  8. from pkg_resources import iter_entry_points
  9. LINTERS: Dict[str, Type[LinterV2]] = {}
  10. if TYPE_CHECKING:
  11. from pylama.context import RunContext
  12. class LinterMeta(type):
  13. """Register linters."""
  14. def __new__(mcs, name, bases, params):
  15. """Register linters."""
  16. cls: Type[LinterV2] = super().__new__(mcs, name, bases, params)
  17. if cls.name is not None:
  18. LINTERS[cls.name] = cls
  19. return cls
  20. class Linter(metaclass=LinterMeta):
  21. """Abstract class for linter plugin."""
  22. name: Optional[str] = None
  23. @classmethod
  24. def add_args(cls, _: ArgumentParser):
  25. """Add options from linters.
  26. The method has to be a classmethod.
  27. """
  28. def run(self, _path: str, **_meta) -> List[Dict[str, Any]]: # noqa
  29. """Legacy method (support old extenstions)."""
  30. return []
  31. class LinterV2(Linter):
  32. """A new linter class."""
  33. def run_check(self, ctx: RunContext):
  34. """Check code."""
  35. # Import default linters
  36. for _, pname, _ in walk_packages([str(Path(__file__).parent)]): # type: ignore
  37. try:
  38. import_module(f"{__name__}.{pname}")
  39. except ImportError:
  40. pass
  41. # Import installed linters
  42. for entry in iter_entry_points("pylama.linter"):
  43. if entry.name not in LINTERS:
  44. try:
  45. LINTERS[entry.name] = entry.load()
  46. except ImportError:
  47. pass