pyreverse.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  2. # For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
  3. # Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
  4. from __future__ import annotations
  5. import argparse
  6. import configparser
  7. import shlex
  8. import sys
  9. from pathlib import Path
  10. from typing import NamedTuple
  11. from pylint.pyreverse.main import DEFAULT_COLOR_PALETTE
  12. if sys.version_info >= (3, 8):
  13. from typing import TypedDict
  14. else:
  15. from typing_extensions import TypedDict
  16. # This class could and should be replaced with a simple dataclass when support for Python < 3.7 is dropped.
  17. # A NamedTuple is not possible as some tests need to modify attributes during the test.
  18. class PyreverseConfig(
  19. argparse.Namespace
  20. ): # pylint: disable=too-many-instance-attributes, too-many-arguments
  21. """Holds the configuration options for Pyreverse.
  22. The default values correspond to the defaults of the options' parser.
  23. """
  24. def __init__(
  25. self,
  26. mode: str = "PUB_ONLY",
  27. classes: list[str] | None = None,
  28. show_ancestors: int | None = None,
  29. all_ancestors: bool | None = None,
  30. show_associated: int | None = None,
  31. all_associated: bool | None = None,
  32. show_builtin: bool = False,
  33. module_names: bool | None = None,
  34. only_classnames: bool = False,
  35. output_format: str = "dot",
  36. colorized: bool = False,
  37. max_color_depth: int = 2,
  38. color_palette: tuple[str, ...] = DEFAULT_COLOR_PALETTE,
  39. ignore_list: tuple[str, ...] = tuple(),
  40. project: str = "",
  41. output_directory: str = "",
  42. ) -> None:
  43. super().__init__()
  44. self.mode = mode
  45. if classes:
  46. self.classes = classes
  47. else:
  48. self.classes = []
  49. self.show_ancestors = show_ancestors
  50. self.all_ancestors = all_ancestors
  51. self.show_associated = show_associated
  52. self.all_associated = all_associated
  53. self.show_builtin = show_builtin
  54. self.module_names = module_names
  55. self.only_classnames = only_classnames
  56. self.output_format = output_format
  57. self.colorized = colorized
  58. self.max_color_depth = max_color_depth
  59. self.color_palette = color_palette
  60. self.ignore_list = ignore_list
  61. self.project = project
  62. self.output_directory = output_directory
  63. class TestFileOptions(TypedDict):
  64. source_roots: list[str]
  65. output_formats: list[str]
  66. command_line_args: list[str]
  67. class FunctionalPyreverseTestfile(NamedTuple):
  68. """Named tuple containing the test file and the expected output."""
  69. source: Path
  70. options: TestFileOptions
  71. def get_functional_test_files(
  72. root_directory: Path,
  73. ) -> list[FunctionalPyreverseTestfile]:
  74. """Get all functional test files from the given directory."""
  75. test_files = []
  76. for path in root_directory.rglob("*.py"):
  77. if path.stem.startswith("_"):
  78. continue
  79. config_file = path.with_suffix(".rc")
  80. if config_file.exists():
  81. test_files.append(
  82. FunctionalPyreverseTestfile(
  83. source=path, options=_read_config(config_file)
  84. )
  85. )
  86. else:
  87. test_files.append(
  88. FunctionalPyreverseTestfile(
  89. source=path,
  90. options={
  91. "source_roots": [],
  92. "output_formats": ["mmd"],
  93. "command_line_args": [],
  94. },
  95. )
  96. )
  97. return test_files
  98. def _read_config(config_file: Path) -> TestFileOptions:
  99. config = configparser.ConfigParser()
  100. config.read(str(config_file))
  101. source_roots = config.get("testoptions", "source_roots", fallback=None)
  102. return {
  103. "source_roots": source_roots.split(",") if source_roots else [],
  104. "output_formats": config.get(
  105. "testoptions", "output_formats", fallback="mmd"
  106. ).split(","),
  107. "command_line_args": shlex.split(
  108. config.get("testoptions", "command_line_args", fallback="")
  109. ),
  110. }