RepoAuditor 0.2.22__tar.gz → 0.2.23__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. {repoauditor-0.2.22 → repoauditor-0.2.23}/PKG-INFO +1 -1
  2. {repoauditor-0.2.22 → repoauditor-0.2.23}/pyproject.toml +1 -1
  3. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/CommandLineProcessor.py +128 -63
  4. repoauditor-0.2.23/src/RepoAuditor/Display.py +165 -0
  5. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/EntryPoint.py +1 -1
  6. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/ExecuteModules.py +73 -177
  7. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/__init__.py +1 -1
  8. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/ExecuteModules_UnitTest.py +1 -0
  9. {repoauditor-0.2.22 → repoauditor-0.2.23}/.copier-answers.yml +0 -0
  10. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/CODEOWNERS +0 -0
  11. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  12. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  13. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/ISSUE_TEMPLATE/custom.md +0 -0
  14. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  15. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/actions/release_impl/action.yml +0 -0
  16. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/pull_request_template.md +0 -0
  17. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/release_sources.yaml +0 -0
  18. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/workflows/CICD.yml +0 -0
  19. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/workflows/CICD_impl.yml +0 -0
  20. {repoauditor-0.2.22 → repoauditor-0.2.23}/.github/workflows/codeql.yml +0 -0
  21. {repoauditor-0.2.22 → repoauditor-0.2.23}/.gitignore +0 -0
  22. {repoauditor-0.2.22 → repoauditor-0.2.23}/.pre-commit-config.yaml +0 -0
  23. {repoauditor-0.2.22 → repoauditor-0.2.23}/.python-version +0 -0
  24. {repoauditor-0.2.22 → repoauditor-0.2.23}/CODE_OF_CONDUCT.md +0 -0
  25. {repoauditor-0.2.22 → repoauditor-0.2.23}/CONTRIBUTING.md +0 -0
  26. {repoauditor-0.2.22 → repoauditor-0.2.23}/DEVELOPMENT.md +0 -0
  27. {repoauditor-0.2.22 → repoauditor-0.2.23}/GOVERNANCE.md +0 -0
  28. {repoauditor-0.2.22 → repoauditor-0.2.23}/LICENSE +0 -0
  29. {repoauditor-0.2.22 → repoauditor-0.2.23}/MAINTAINERS.md +0 -0
  30. {repoauditor-0.2.22 → repoauditor-0.2.23}/README.md +0 -0
  31. {repoauditor-0.2.22 → repoauditor-0.2.23}/SECURITY.md +0 -0
  32. {repoauditor-0.2.22 → repoauditor-0.2.23}/minisign_key.pub +0 -0
  33. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/AutoGitSemVer.yaml +0 -0
  34. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Impl/ParallelSequentialProcessor.py +0 -0
  35. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Impl/__init__.py +0 -0
  36. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Module.py +0 -0
  37. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugin.py +0 -0
  38. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionQuery.py +0 -0
  39. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/AllowDeletions.py +0 -0
  40. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/AllowForcePushes.py +0 -0
  41. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/DismissStalePullRequestApprovals.py +0 -0
  42. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/DoNotAllowBypassSettings.py +0 -0
  43. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/EnsureStatusChecks.py +0 -0
  44. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/ClassicEnableRequirementImpl.py +0 -0
  45. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/ClassicValueRequirementImpl.py +0 -0
  46. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/__init__.py +0 -0
  47. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireApprovalMostRecentPush.py +0 -0
  48. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireApprovals.py +0 -0
  49. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireCodeOwnerReview.py +0 -0
  50. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireConversationResolution.py +0 -0
  51. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireLinearHistory.py +0 -0
  52. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequirePullRequests.py +0 -0
  53. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireSignedCommits.py +0 -0
  54. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireStatusChecksToPass.py +0 -0
  55. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireUpToDateBranches.py +0 -0
  56. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/__init__.py +0 -0
  57. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQuery.py +0 -0
  58. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQueryRequirements/Protected.py +0 -0
  59. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQueryRequirements/__init__.py +0 -0
  60. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/Impl/Common.py +0 -0
  61. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/Impl/EnableRequirementImpl.py +0 -0
  62. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/Impl/ValueRequirementImpl.py +0 -0
  63. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/Impl/__init__.py +0 -0
  64. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/Module.py +0 -0
  65. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQuery.py +0 -0
  66. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/AutoMerge.py +0 -0
  67. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DefaultBranch.py +0 -0
  68. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DeleteHeadBranches.py +0 -0
  69. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DependabotSecurityUpdates.py +0 -0
  70. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Description.py +0 -0
  71. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/StandardEnableRequirementImpl.py +0 -0
  72. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/StandardValueRequirementImpl.py +0 -0
  73. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/__init__.py +0 -0
  74. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/License.py +0 -0
  75. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/MergeCommit.py +0 -0
  76. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/MergeCommitMessage.py +0 -0
  77. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Private.py +0 -0
  78. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/RebaseMergeCommit.py +0 -0
  79. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SecretScanning.py +0 -0
  80. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SecretScanningPushProtection.py +0 -0
  81. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SquashCommitMerge.py +0 -0
  82. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SquashMergeCommitMessage.py +0 -0
  83. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SuggestUpdatingPullRequestBranches.py +0 -0
  84. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportDiscussions.py +0 -0
  85. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportIssues.py +0 -0
  86. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportProjects.py +0 -0
  87. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportWikis.py +0 -0
  88. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/TemplateRepository.py +0 -0
  89. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/WebCommitSignoff.py +0 -0
  90. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/__init__.py +0 -0
  91. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHub/__init__.py +0 -0
  92. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHubBase/Module.py +0 -0
  93. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHubBase/__init__.py +0 -0
  94. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHubCustomization/CustomizationQuery.py +0 -0
  95. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHubCustomization/Module.py +0 -0
  96. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHubCustomization/__init__.py +0 -0
  97. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHubCustomizationPlugin.py +0 -0
  98. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/GitHubPlugin.py +0 -0
  99. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Plugins/__init__.py +0 -0
  100. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Query.py +0 -0
  101. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/Requirement.py +0 -0
  102. {repoauditor-0.2.22 → repoauditor-0.2.23}/src/RepoAuditor/py.typed +0 -0
  103. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/CommandLineProcessor_UnitTest.py +0 -0
  104. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/EntryPoint_UnitTest.py +0 -0
  105. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Module_UnitTest.py +0 -0
  106. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Plugin_UnitTest.py +0 -0
  107. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Plugins/GitHubCustomization_UnitTest.py +0 -0
  108. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Plugins/GitHubModule_UnitTest.py +0 -0
  109. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Plugins/GitHub_EndToEndTest.py +0 -0
  110. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Plugins/__snapshots__/GitHub_EndToEndTest.ambr +0 -0
  111. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Plugins/utilities.py +0 -0
  112. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Query_UnitTest.py +0 -0
  113. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/Requirement_UnitTest.py +0 -0
  114. {repoauditor-0.2.22 → repoauditor-0.2.23}/tests/__snapshots__/ExecuteModules_UnitTest.ambr +0 -0
  115. {repoauditor-0.2.22 → repoauditor-0.2.23}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RepoAuditor
3
- Version: 0.2.22
3
+ Version: 0.2.23
4
4
  Summary: Add your description here
5
5
  Project-URL: Homepage, https://github.com/gt-sse-center/RepoAuditor
6
6
  Project-URL: Documentation, https://github.com/gt-sse-center/RepoAuditor
@@ -119,7 +119,7 @@ select = [
119
119
  "PTH",
120
120
  "FLY",
121
121
  "I",
122
- # "C90", # 3
122
+ "C90",
123
123
  "NPY",
124
124
  "PD",
125
125
  "N",
@@ -36,38 +36,15 @@ class CommandLineProcessor:
36
36
  ], # actual type is dict[str, TyperEx.TypeDefinitionItemType]
37
37
  ) -> dict[str, Any]: ...
38
38
 
39
- # ----------------------------------------------------------------------
40
- # |
41
- # | Public Data
42
- # |
43
- # ----------------------------------------------------------------------
44
- module_infos: list[ModuleInfo]
45
- warnings_as_error_module_names: set[str]
46
- ignore_warnings_module_names: set[str]
47
- single_threaded: bool = field(kw_only=True)
48
-
49
- # ----------------------------------------------------------------------
50
- # |
51
- # | Public Methods
52
- # |
53
- # ----------------------------------------------------------------------
54
- @classmethod
55
- def Create(
56
- cls,
57
- get_dynamic_args_func: "CommandLineProcessor.GetDynamicArgsFunc",
39
+ @staticmethod
40
+ def _GetModuleMap(
58
41
  modules: list[Module],
59
- includes: list[str],
60
- excludes: list[str],
61
- warnings_as_error_module_names: set[str],
62
- ignore_warnings_module_names: set[str],
63
- *,
64
- all_warnings_as_error: bool = False,
65
- ignore_all_warnings: bool = False,
66
- single_threaded: bool = False,
67
- argument_separator: str = "-",
68
- ) -> "CommandLineProcessor":
69
- """Factor method to construct a CommandLineProcessor object."""
70
- # Convert modules into a lookup map
42
+ argument_separator: str,
43
+ ) -> dict[str, Module]:
44
+ """Convert modules into a lookup map.
45
+
46
+ Returns a dict of module names mapped to the corresponding module.
47
+ """
71
48
  module_map: dict[str, Module] = {}
72
49
 
73
50
  for module in modules:
@@ -75,16 +52,26 @@ class CommandLineProcessor:
75
52
  msg = f"The module name '{module.name}' contains '{argument_separator}', which should be used as an argument separator."
76
53
  raise ValueError(msg)
77
54
 
78
- prev_module = module_map.get(module.name, None)
79
- if prev_module is not None:
55
+ prev_added_module = module_map.get(module.name, None)
56
+ if prev_added_module is not None:
80
57
  msg = f"The module '{module.name}' has already been defined."
81
58
  raise ValueError(msg)
82
59
 
83
60
  module_map[module.name] = module
84
61
 
85
- del modules
62
+ return module_map
86
63
 
87
- # Process includes
64
+ @staticmethod
65
+ def _ProcessIncludes(
66
+ module_map: dict[str, Module],
67
+ includes: list[str],
68
+ argument_separator: str,
69
+ ) -> tuple[set[str], dict[str, set[str]]]:
70
+ """Process the modules and requirements to include.
71
+
72
+ Returns both the set of names of the included modules as well as
73
+ the dictionary of module names mapped to the set of included requirement names.
74
+ """
88
75
  included_modules: set[str] = set()
89
76
  included_requirements: dict[str, set[str]] = {}
90
77
 
@@ -103,16 +90,19 @@ class CommandLineProcessor:
103
90
  argument_separator.join(parts[1:])
104
91
  )
105
92
 
106
- del includes
93
+ return included_modules, included_requirements
107
94
 
108
- for module_name, module in list(module_map.items()):
109
- if module.requires_explicit_include and module_name not in included_modules:
110
- module_map.pop(module_name)
111
- continue
112
-
113
- del included_modules
95
+ @staticmethod
96
+ def _ProcessExcludes(
97
+ module_map: dict[str, Module],
98
+ excludes: list[str],
99
+ argument_separator: str,
100
+ ) -> dict[str, set[str]]:
101
+ """Process the modules and requirements to exclude.
114
102
 
115
- # Process excludes
103
+ Returns both the set of names of the excluded modules as well as
104
+ the dictionary of module names mapped to the set of excluded requirement names.
105
+ """
116
106
  excluded_requirements: dict[str, set[str]] = {}
117
107
 
118
108
  for exclude in excludes:
@@ -130,27 +120,20 @@ class CommandLineProcessor:
130
120
  argument_separator.join(parts[1:])
131
121
  )
132
122
 
133
- del excludes
134
-
135
- # Add / Remove the requirements for each module
136
- for module_name, module in list(module_map.items()):
137
- module.ProcessRequirements(
138
- included_requirements.get(module_name, set()),
139
- excluded_requirements.get(module_name, set()),
140
- )
123
+ return excluded_requirements
141
124
 
142
- if module.GetNumRequirements() == 0:
143
- module_map.pop(module_name)
144
-
145
- del included_requirements
146
- del excluded_requirements
147
-
148
- if all_warnings_as_error:
149
- warnings_as_error_module_names = {module.name for module in module_map.values()}
150
- if ignore_all_warnings:
151
- ignore_warnings_module_names = {module.name for module in module_map.values()}
125
+ @staticmethod
126
+ def _ProcessDynamicArguments(
127
+ module_map: dict[str, Module],
128
+ argument_separator: str,
129
+ get_dynamic_args_func: "CommandLineProcessor.GetDynamicArgsFunc",
130
+ ) -> dict[str, dict[str, Any]]:
131
+ """Process the passed in dynamic arguments.
152
132
 
153
- # Create the type definitions
133
+ Returns a dictionary of module names to a corresponding dictionary
134
+ of argument names to values.
135
+ """
136
+ # First we create the type definitions
154
137
  dynamic_arg_definitions: dict[str, Any] = {}
155
138
 
156
139
  for module in module_map.values():
@@ -166,7 +149,7 @@ class CommandLineProcessor:
166
149
  f"{module.name}{argument_separator}{requirement.name}{argument_separator}{key}"
167
150
  ] = value
168
151
 
169
- # Process the dynamic info
152
+ # Now we process the definitions to get the dynamic arguments
170
153
  dynamic_args: dict[str, dict[str, Any]] = {}
171
154
 
172
155
  for key, value in get_dynamic_args_func(dynamic_arg_definitions).items():
@@ -185,6 +168,88 @@ class CommandLineProcessor:
185
168
  {},
186
169
  )[argument_separator.join(parts[2:])] = value
187
170
 
171
+ return dynamic_args
172
+
173
+ # ----------------------------------------------------------------------
174
+ # |
175
+ # | Public Data
176
+ # |
177
+ # ----------------------------------------------------------------------
178
+ module_infos: list[ModuleInfo]
179
+ warnings_as_error_module_names: set[str]
180
+ ignore_warnings_module_names: set[str]
181
+ single_threaded: bool = field(kw_only=True)
182
+
183
+ # ----------------------------------------------------------------------
184
+ # |
185
+ # | Public Methods
186
+ # |
187
+ # ----------------------------------------------------------------------
188
+ @classmethod
189
+ def Create(
190
+ cls,
191
+ get_dynamic_args_func: "CommandLineProcessor.GetDynamicArgsFunc",
192
+ modules: list[Module],
193
+ includes: list[str],
194
+ excludes: list[str],
195
+ warnings_as_error_module_names: set[str],
196
+ ignore_warnings_module_names: set[str],
197
+ *,
198
+ all_warnings_as_error: bool = False,
199
+ ignore_all_warnings: bool = False,
200
+ single_threaded: bool = False,
201
+ argument_separator: str = "-",
202
+ ) -> "CommandLineProcessor":
203
+ """Factor method to construct a CommandLineProcessor object."""
204
+ # Convert modules into a lookup map
205
+ module_map: dict[str, Module] = cls._GetModuleMap(modules, argument_separator)
206
+
207
+ del modules
208
+
209
+ # Process includes
210
+ included_modules, included_requirements = cls._ProcessIncludes(
211
+ module_map, includes, argument_separator
212
+ )
213
+
214
+ del includes
215
+
216
+ for module_name, module in list(module_map.items()):
217
+ if module.requires_explicit_include and module_name not in included_modules:
218
+ module_map.pop(module_name)
219
+ continue
220
+
221
+ del included_modules
222
+
223
+ # Process excludes
224
+ excluded_requirements: dict[str, set[str]] = cls._ProcessExcludes(
225
+ module_map, excludes, argument_separator
226
+ )
227
+
228
+ del excludes
229
+
230
+ # Add / Remove the requirements for each module
231
+ for module_name, module in list(module_map.items()):
232
+ module.ProcessRequirements(
233
+ included_requirements.get(module_name, set()),
234
+ excluded_requirements.get(module_name, set()),
235
+ )
236
+
237
+ if module.GetNumRequirements() == 0:
238
+ module_map.pop(module_name)
239
+
240
+ del included_requirements
241
+ del excluded_requirements
242
+
243
+ if all_warnings_as_error:
244
+ warnings_as_error_module_names = {module.name for module in module_map.values()}
245
+ if ignore_all_warnings:
246
+ ignore_warnings_module_names = {module.name for module in module_map.values()}
247
+
248
+ # Process the dynamic info
249
+ dynamic_args: dict[str, dict[str, Any]] = cls._ProcessDynamicArguments(
250
+ module_map, argument_separator, get_dynamic_args_func
251
+ )
252
+
188
253
  module_infos: list[ModuleInfo] = []
189
254
 
190
255
  for module_name, module in module_map.items():
@@ -0,0 +1,165 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains functionality to display the results of executing modules."""
8
+
9
+ import textwrap
10
+ from typing import Optional
11
+
12
+ from dbrownell_Common.Streams.DoneManager import DoneManager # type: ignore[import-untyped]
13
+ from dbrownell_Common import TextwrapEx # type: ignore[import-untyped]
14
+ from rich import print as rich_print
15
+ from rich.console import Group
16
+ from rich.panel import Panel
17
+
18
+ from .Module import EvaluateResult, Module
19
+
20
+
21
+ def GetInternalPanelContent(
22
+ dm: DoneManager,
23
+ results: list[Module.EvaluateInfo],
24
+ display_resolution: bool,
25
+ display_rationale: bool,
26
+ num_success: int,
27
+ num_warning: int,
28
+ num_error: int,
29
+ num_does_not_apply: int,
30
+ num_requirements: int,
31
+ ) -> list[Panel | str]:
32
+ """Get the content for each result to be displayed inside the internal panel."""
33
+ internal_content: list[Panel | str] = []
34
+
35
+ module = results[0].module
36
+
37
+ if module.description:
38
+ internal_content.append(f"{module.description.strip()}\n")
39
+
40
+ internal_content.append(
41
+ textwrap.dedent(
42
+ f"""\
43
+ Successful: {num_success} ({(num_success / num_requirements):.02%})
44
+ Warnings: {num_warning} ({(num_warning / num_requirements):.02%})
45
+ Errors: {num_error} ({(num_error / num_requirements):.02%})
46
+ Skipped: {num_does_not_apply} ({(num_does_not_apply / num_requirements):.02%})
47
+ """,
48
+ ),
49
+ )
50
+
51
+ for result in results:
52
+ if not dm.is_verbose and result.result in [
53
+ EvaluateResult.Success,
54
+ EvaluateResult.DoesNotApply,
55
+ ]:
56
+ continue
57
+
58
+ if result.result == EvaluateResult.Success:
59
+ border_color = "green"
60
+ elif result.result == EvaluateResult.Warning:
61
+ border_color = "yellow"
62
+ elif result.result == EvaluateResult.Error:
63
+ border_color = "red"
64
+ elif result.result == EvaluateResult.DoesNotApply:
65
+ border_color = ""
66
+ else:
67
+ raise RuntimeError(result.result) # pragma: no cover
68
+
69
+ content: list[str] = []
70
+
71
+ if result.requirement.description:
72
+ content.append(f"{result.requirement.description.strip()}\n")
73
+
74
+ if result.context:
75
+ content.append(f"{result.result.name.upper()}: {result.context.strip()}\n")
76
+
77
+ if display_resolution and result.resolution:
78
+ content.append(
79
+ textwrap.dedent(
80
+ """\
81
+ Resolution
82
+ ----------
83
+ {}
84
+ """,
85
+ ).format(TextwrapEx.Indent(result.resolution.strip(), 2, skip_first_line=True)),
86
+ )
87
+
88
+ if display_rationale and result.rationale:
89
+ content.append(
90
+ textwrap.dedent(
91
+ """\
92
+ Rationale
93
+ ---------
94
+ {}
95
+ """,
96
+ ).format(TextwrapEx.Indent(result.rationale.strip(), 2, skip_first_line=True)),
97
+ )
98
+
99
+ internal_content.append(
100
+ Panel(
101
+ Group(*content),
102
+ title=f"[{result.result.name}] {result.requirement.name}",
103
+ title_align="left",
104
+ border_style=border_color,
105
+ padding=(1, 1, 0, 1) if content else 0,
106
+ ),
107
+ )
108
+
109
+ return internal_content
110
+
111
+
112
+ # ----------------------------------------------------------------------
113
+ def DisplayResults(
114
+ dm: DoneManager,
115
+ all_results: list[list[Module.EvaluateInfo]],
116
+ *,
117
+ display_resolution: bool,
118
+ display_rationale: bool,
119
+ panel_width: Optional[int] = None,
120
+ ) -> None:
121
+ """Display the results of executing the modules."""
122
+ for results in all_results:
123
+ assert results
124
+ module = results[0].module
125
+
126
+ num_success = 0
127
+ num_warning = 0
128
+ num_error = 0
129
+ num_does_not_apply = 0
130
+
131
+ for result in results:
132
+ if result.result == EvaluateResult.Success:
133
+ num_success += 1
134
+ elif result.result == EvaluateResult.Warning:
135
+ num_warning += 1
136
+ elif result.result == EvaluateResult.Error:
137
+ num_error += 1
138
+ elif result.result == EvaluateResult.DoesNotApply:
139
+ num_does_not_apply += 1
140
+ else:
141
+ raise RuntimeError(result.result) # pragma: no cover
142
+
143
+ num_requirements = module.GetNumRequirements()
144
+ assert num_requirements
145
+
146
+ internal_content: list[Panel | str] = GetInternalPanelContent(
147
+ dm,
148
+ results,
149
+ display_resolution,
150
+ display_rationale,
151
+ num_success=num_success,
152
+ num_warning=num_warning,
153
+ num_error=num_error,
154
+ num_does_not_apply=num_does_not_apply,
155
+ num_requirements=num_requirements,
156
+ )
157
+
158
+ rich_print(
159
+ Panel(
160
+ Group(*internal_content),
161
+ padding=1 if internal_content else 0,
162
+ title=results[0].module.name,
163
+ width=panel_width,
164
+ ),
165
+ )
@@ -23,7 +23,7 @@ from typer.core import TyperGroup # type: ignore [import-untyped]
23
23
 
24
24
  from RepoAuditor import APP_NAME, __version__
25
25
  from RepoAuditor.CommandLineProcessor import CommandLineProcessor, Module
26
- from RepoAuditor.ExecuteModules import DisplayResults
26
+ from RepoAuditor.Display import DisplayResults
27
27
  from RepoAuditor import Plugin
28
28
 
29
29
 
@@ -8,7 +8,6 @@
8
8
 
9
9
  import itertools
10
10
  import sys
11
- import textwrap
12
11
 
13
12
  from dataclasses import dataclass
14
13
  from typing import Any, cast, Optional
@@ -18,10 +17,6 @@ from dbrownell_Common import ExecuteTasks # type: ignore[import-untyped]
18
17
  from dbrownell_Common.InflectEx import inflect # type: ignore[import-untyped]
19
18
  from dbrownell_Common.Streams.Capabilities import Capabilities # type: ignore[import-untyped]
20
19
  from dbrownell_Common.Streams.DoneManager import DoneManager # type: ignore[import-untyped]
21
- from dbrownell_Common import TextwrapEx # type: ignore[import-untyped]
22
- from rich import print as rich_print
23
- from rich.console import Group
24
- from rich.panel import Panel
25
20
  from rich.progress import Progress, TimeElapsedColumn
26
21
 
27
22
  from .Module import EvaluateResult, ExecutionStyle, Module, OnStatusFunc
@@ -46,6 +41,66 @@ class ModuleInfo:
46
41
  # | Public Functions
47
42
  # |
48
43
  # ----------------------------------------------------------------------
44
+
45
+
46
+ # ----------------------------------------------------------------------
47
+ def Evaluate(
48
+ module_info: ModuleInfo,
49
+ on_status_func: OnStatusFunc,
50
+ max_num_threads: Optional[int],
51
+ ) -> list[list[Module.EvaluateInfo]]:
52
+ """Evaluate the module given the dynamic arguments.
53
+
54
+ Returns a list of information pertaining to module evaluation,
55
+ with it subgrouped as lists themselves, hence a list of lists.
56
+ """
57
+ module_data = module_info.module.GenerateInitialData(module_info.dynamic_args)
58
+ if module_data is None:
59
+ return []
60
+
61
+ return module_info.module.Evaluate(
62
+ module_data,
63
+ module_info.requirement_args,
64
+ on_status_func,
65
+ max_num_threads=max_num_threads,
66
+ )
67
+
68
+
69
+ # ----------------------------------------------------------------------
70
+ def CalcResultInfo(
71
+ all_eval_infos: list[list[Module.EvaluateInfo]],
72
+ warnings_as_errors_module_names: set[str],
73
+ ignore_warnings_module_names: set[str],
74
+ ) -> tuple[int, str]:
75
+ """Calculate the result of evaluating the modules as given in `all_eval_infos`.
76
+
77
+ Returns a code value indicating success, warning, or error,
78
+ as well as a string description of the result.
79
+ """
80
+ return_code = 0
81
+
82
+ if not all_eval_infos:
83
+ return 0, "module does not apply"
84
+
85
+ for eval_infos in all_eval_infos:
86
+ for eval_info in eval_infos:
87
+ result = eval_info.result
88
+
89
+ if result == EvaluateResult.Warning:
90
+ if eval_info.module.name in warnings_as_errors_module_names:
91
+ result = EvaluateResult.Error
92
+ elif eval_info.module.name in ignore_warnings_module_names:
93
+ continue
94
+
95
+ if result == EvaluateResult.Error:
96
+ return -1, "errors were encountered"
97
+
98
+ if result == EvaluateResult.Warning:
99
+ return_code = 1
100
+
101
+ return return_code, "" if return_code == 0 else "warnings were encountered"
102
+
103
+
49
104
  def Execute(
50
105
  dm: DoneManager,
51
106
  module_infos: list[ModuleInfo],
@@ -82,52 +137,7 @@ def Execute(
82
137
  parallel = []
83
138
 
84
139
  # Calculate the results
85
-
86
140
  # ----------------------------------------------------------------------
87
- def Evaluate(
88
- module_info: ModuleInfo,
89
- on_status_func: OnStatusFunc,
90
- ) -> list[list[Module.EvaluateInfo]]:
91
- module_data = module_info.module.GenerateInitialData(module_info.dynamic_args)
92
- if module_data is None:
93
- return []
94
-
95
- return module_info.module.Evaluate(
96
- module_data,
97
- module_info.requirement_args,
98
- on_status_func,
99
- max_num_threads=max_num_threads,
100
- )
101
-
102
- # ----------------------------------------------------------------------
103
- def CalcResultInfo(
104
- all_eval_infos: list[list[Module.EvaluateInfo]],
105
- ) -> tuple[int, str]:
106
- return_code = 0
107
-
108
- if not all_eval_infos:
109
- return 0, "module does not apply"
110
-
111
- for eval_infos in all_eval_infos:
112
- for eval_info in eval_infos:
113
- result = eval_info.result
114
-
115
- if result == EvaluateResult.Warning:
116
- if eval_info.module.name in warnings_as_errors_module_names:
117
- result = EvaluateResult.Error
118
- elif eval_info.module.name in ignore_warnings_module_names:
119
- continue
120
-
121
- if result == EvaluateResult.Error:
122
- return -1, "errors were encountered"
123
-
124
- if result == EvaluateResult.Warning:
125
- return_code = 1
126
-
127
- return return_code, "" if return_code == 0 else "warnings were encountered"
128
-
129
- # ----------------------------------------------------------------------
130
-
131
141
  all_results: list[Optional[list[list[Module.EvaluateInfo]]]] = [None] * len(module_infos)
132
142
 
133
143
  if parallel:
@@ -152,9 +162,13 @@ def Execute(
152
162
 
153
163
  # ----------------------------------------------------------------------
154
164
 
155
- evaluate_results = Evaluate(module_info, OnStatus)
165
+ evaluate_results = Evaluate(module_info, OnStatus, max_num_threads=max_num_threads)
156
166
 
157
- result_code, result_status = CalcResultInfo(evaluate_results)
167
+ result_code, result_status = CalcResultInfo(
168
+ evaluate_results,
169
+ warnings_as_errors_module_names=warnings_as_errors_module_names,
170
+ ignore_warnings_module_names=ignore_warnings_module_names,
171
+ )
158
172
 
159
173
  return ExecuteTasks.TransformResultComplete(evaluate_results, result_code, result_status)
160
174
 
@@ -186,11 +200,7 @@ def Execute(
186
200
  for index, (all_results_index, module_info) in enumerate(sequential):
187
201
  with (
188
202
  modules_dm.Nested(
189
- "Processing '{}' ({} of {})...".format(
190
- module_info.module.name,
191
- index + 1 + len(parallel),
192
- len(module_infos),
193
- ),
203
+ f"Processing '{module_info.module.name}' ({index + 1 + len(parallel)} of {len(module_infos)})...",
194
204
  ) as this_module_dm,
195
205
  # rich.progress needs to output to sys.stdout
196
206
  this_module_dm.YieldStdout() as stdout_context,
@@ -243,12 +253,16 @@ def Execute(
243
253
 
244
254
  # ----------------------------------------------------------------------
245
255
 
246
- evaluate_results = Evaluate(module_info, OnStatus)
256
+ evaluate_results = Evaluate(module_info, OnStatus, max_num_threads=max_num_threads)
247
257
 
248
258
  assert all_results[all_results_index] is None
249
259
  all_results[all_results_index] = evaluate_results
250
260
 
251
- this_module_dm.result = CalcResultInfo(evaluate_results)[0]
261
+ this_module_dm.result = CalcResultInfo(
262
+ evaluate_results,
263
+ warnings_as_errors_module_names=warnings_as_errors_module_names,
264
+ ignore_warnings_module_names=ignore_warnings_module_names,
265
+ )[0]
252
266
 
253
267
  final_results: list[list[Module.EvaluateInfo]] = []
254
268
 
@@ -261,124 +275,6 @@ def Execute(
261
275
  return final_results
262
276
 
263
277
 
264
- # ----------------------------------------------------------------------
265
- def DisplayResults(
266
- dm: DoneManager,
267
- all_results: list[list[Module.EvaluateInfo]],
268
- *,
269
- display_resolution: bool,
270
- display_rationale: bool,
271
- panel_width: Optional[int] = None,
272
- ) -> None:
273
- """Display the results of executing the modules."""
274
- for results in all_results:
275
- assert results
276
- module = results[0].module
277
-
278
- num_success = 0
279
- num_warning = 0
280
- num_error = 0
281
- num_does_not_apply = 0
282
-
283
- for result in results:
284
- if result.result == EvaluateResult.Success:
285
- num_success += 1
286
- elif result.result == EvaluateResult.Warning:
287
- num_warning += 1
288
- elif result.result == EvaluateResult.Error:
289
- num_error += 1
290
- elif result.result == EvaluateResult.DoesNotApply:
291
- num_does_not_apply += 1
292
- else:
293
- raise RuntimeError(result.result) # pragma: no cover
294
-
295
- num_requirements = module.GetNumRequirements()
296
- assert num_requirements
297
-
298
- internal_content: list[Panel | str] = []
299
-
300
- if module.description:
301
- internal_content.append(f"{module.description.strip()}\n")
302
-
303
- internal_content.append(
304
- textwrap.dedent(
305
- f"""\
306
- Successful: {num_success} ({(num_success / num_requirements):.02%})
307
- Warnings: {num_warning} ({(num_warning / num_requirements):.02%})
308
- Errors: {num_error} ({(num_error / num_requirements):.02%})
309
- Skipped: {num_does_not_apply} ({(num_does_not_apply / num_requirements):.02%})
310
- """,
311
- ),
312
- )
313
-
314
- for result in results:
315
- if not dm.is_verbose and result.result in [
316
- EvaluateResult.Success,
317
- EvaluateResult.DoesNotApply,
318
- ]:
319
- continue
320
-
321
- if result.result == EvaluateResult.Success:
322
- border_color = "green"
323
- elif result.result == EvaluateResult.Warning:
324
- border_color = "yellow"
325
- elif result.result == EvaluateResult.Error:
326
- border_color = "red"
327
- elif result.result == EvaluateResult.DoesNotApply:
328
- border_color = ""
329
- else:
330
- raise RuntimeError(result.result) # pragma: no cover
331
-
332
- content: list[str] = []
333
-
334
- if result.requirement.description:
335
- content.append(f"{result.requirement.description.strip()}\n")
336
-
337
- if result.context:
338
- content.append(f"{result.result.name.upper()}: {result.context.strip()}\n")
339
-
340
- if display_resolution and result.resolution:
341
- content.append(
342
- textwrap.dedent(
343
- """\
344
- Resolution
345
- ----------
346
- {}
347
- """,
348
- ).format(TextwrapEx.Indent(result.resolution.strip(), 2, skip_first_line=True)),
349
- )
350
-
351
- if display_rationale and result.rationale:
352
- content.append(
353
- textwrap.dedent(
354
- """\
355
- Rationale
356
- ---------
357
- {}
358
- """,
359
- ).format(TextwrapEx.Indent(result.rationale.strip(), 2, skip_first_line=True)),
360
- )
361
-
362
- internal_content.append(
363
- Panel(
364
- Group(*content),
365
- title=f"[{result.result.name}] {result.requirement.name}",
366
- title_align="left",
367
- border_style=border_color,
368
- padding=(1, 1, 0, 1) if content else 0,
369
- ),
370
- )
371
-
372
- rich_print(
373
- Panel(
374
- Group(*internal_content),
375
- padding=1 if internal_content else 0,
376
- title=results[0].module.name,
377
- width=panel_width,
378
- ),
379
- )
380
-
381
-
382
278
  # ----------------------------------------------------------------------
383
279
  # ----------------------------------------------------------------------
384
280
  # ----------------------------------------------------------------------
@@ -3,4 +3,4 @@ APP_NAME = "RepoAuditor"
3
3
  # Note that this value will be overwritten by calls to `python ../../Build.py update_version` based
4
4
  # on changes observed in the git repository. The default value below will be used until the value
5
5
  # here is explicitly updated by the Continuous Integration system.
6
- __version__ = "0.2.22"
6
+ __version__ = "0.2.23"
@@ -20,6 +20,7 @@ from dbrownell_Common.TestHelpers.StreamTestHelpers import (
20
20
  InitializeStreamCapabilities,
21
21
  )
22
22
 
23
+ from RepoAuditor.Display import *
23
24
  from RepoAuditor.ExecuteModules import *
24
25
  from RepoAuditor.Module import *
25
26
  from RepoAuditor.Requirement import *
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes