CLASPLint 0.4.0__tar.gz → 0.4.2__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.
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/__init__.py +5 -5
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/__main__.py +30 -14
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/comment_checker.py +21 -33
- CLASPLint-0.4.2/CLASPLint/configuration.py +306 -0
- CLASPLint-0.4.2/CLASPLint/configuration.yaml +692 -0
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/dict_key_checker.py +5 -5
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/docstring_checker.py +6 -20
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/function_checker.py +2 -2
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/log_checker.py +2 -2
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/naming_utils.py +38 -186
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/reporter.py +6 -16
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/runner.py +2 -2
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint/variable_checker.py +9 -9
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint.egg-info/PKG-INFO +81 -58
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint.egg-info/SOURCES.txt +4 -2
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/MANIFEST.in +1 -0
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/PKG-INFO +81 -58
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/README.md +80 -57
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/pyproject.toml +5 -2
- CLASPLint-0.4.2/setup.py +156 -0
- CLASPLint-0.4.0/setup.py +0 -39
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint.egg-info/dependency_links.txt +0 -0
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint.egg-info/entry_points.txt +0 -0
- /CLASPLint-0.4.0/CLASPLint.egg-info/zip-safe → /CLASPLint-0.4.2/CLASPLint.egg-info/not-zip-safe +0 -0
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/CLASPLint.egg-info/top_level.txt +0 -0
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/LICENSE +0 -0
- {CLASPLint-0.4.0 → CLASPLint-0.4.2}/setup.cfg +0 -0
|
@@ -23,16 +23,16 @@ MAINTAINER :
|
|
|
23
23
|
|
|
24
24
|
PROJECT CREATE DATE : 2026-06-17
|
|
25
25
|
|
|
26
|
-
PROJECT VERSION DATE : 2026-07-
|
|
26
|
+
PROJECT VERSION DATE : 2026-07-06
|
|
27
27
|
|
|
28
|
-
PROJECT VERSION : 0.4.
|
|
28
|
+
PROJECT VERSION : 0.4.2
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
FILE CREATE DATE : 2026-06-17
|
|
32
32
|
|
|
33
|
-
FILE VERSION DATE : 2026-07-
|
|
33
|
+
FILE VERSION DATE : 2026-07-06
|
|
34
34
|
|
|
35
|
-
FILE VERSION : 0.4.
|
|
35
|
+
FILE VERSION : 0.4.1
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
STATUS : Stable
|
|
@@ -73,6 +73,6 @@ Sort License:
|
|
|
73
73
|
"""
|
|
74
74
|
|
|
75
75
|
# Define the package version string.
|
|
76
|
-
__version__ = "0.4.
|
|
76
|
+
__version__ = "0.4.2"
|
|
77
77
|
# Expose the runner and reporter modules as the public API.
|
|
78
78
|
__all__ = ["runner", "reporter"]
|
|
@@ -21,16 +21,16 @@ MAINTAINER :
|
|
|
21
21
|
|
|
22
22
|
PROJECT CREATE DATE : 2026-06-17
|
|
23
23
|
|
|
24
|
-
PROJECT VERSION DATE : 2026-07-
|
|
24
|
+
PROJECT VERSION DATE : 2026-07-06
|
|
25
25
|
|
|
26
|
-
PROJECT VERSION : 0.4.
|
|
26
|
+
PROJECT VERSION : 0.4.2
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
FILE CREATE DATE : 2026-06-17
|
|
30
30
|
|
|
31
|
-
FILE VERSION DATE : 2026-07-
|
|
31
|
+
FILE VERSION DATE : 2026-07-06
|
|
32
32
|
|
|
33
|
-
FILE VERSION : 0.4.
|
|
33
|
+
FILE VERSION : 0.4.1
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
STATUS : Stable
|
|
@@ -81,7 +81,14 @@ from . import __version__
|
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
def _init_build_parser_function_() -> argparse.ArgumentParser:
|
|
84
|
-
"""Construct the argument parser for the CLASPLint
|
|
84
|
+
"""Construct the argument parser for the CLASPLint command-line interface.
|
|
85
|
+
|
|
86
|
+
Registers positional paths, --version, --no-recursive, --quiet,
|
|
87
|
+
and --category arguments on a new ArgumentParser instance.
|
|
88
|
+
|
|
89
|
+
:return: A configured ArgumentParser ready for parse_args.
|
|
90
|
+
:rtype: argparse.ArgumentParser
|
|
91
|
+
"""
|
|
85
92
|
# Create the top-level argument parser with a description.
|
|
86
93
|
parser_result = argparse.ArgumentParser(
|
|
87
94
|
# Set the program name displayed in help text.
|
|
@@ -141,15 +148,24 @@ def _init_build_parser_function_() -> argparse.ArgumentParser:
|
|
|
141
148
|
|
|
142
149
|
|
|
143
150
|
def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
144
|
-
"""Execute the CLASPLint analysis and return an exit code
|
|
151
|
+
"""Execute the CLASPLint analysis and return an exit code.
|
|
152
|
+
|
|
153
|
+
Parses command-line arguments, resolves input paths, dispatches
|
|
154
|
+
to the runner, applies category filters, and prints the report.
|
|
155
|
+
|
|
156
|
+
:param argv: Optional list of command-line argument strings.
|
|
157
|
+
:type argv: Optional[Sequence[str]]
|
|
158
|
+
:return: Exit code 0 when no violations are found, 1 otherwise.
|
|
159
|
+
:rtype: int
|
|
160
|
+
"""
|
|
145
161
|
# Build and parse command-line arguments.
|
|
146
|
-
|
|
162
|
+
command_parser = _init_build_parser_function_()
|
|
147
163
|
# Parse the provided arguments or default to sys.argv.
|
|
148
|
-
|
|
164
|
+
parsed_options = command_parser.parse_args(argv)
|
|
149
165
|
# Resolve all input paths to absolute paths for consistent processing.
|
|
150
166
|
list_resolved = []
|
|
151
167
|
# Iterate over each provided path argument.
|
|
152
|
-
for string_path in
|
|
168
|
+
for string_path in parsed_options.paths:
|
|
153
169
|
# Convert the path to an absolute path.
|
|
154
170
|
string_absolute = os.path.abspath(string_path)
|
|
155
171
|
# Only include paths that exist on the filesystem.
|
|
@@ -163,23 +179,23 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
163
179
|
# Return exit code 2 for usage errors.
|
|
164
180
|
return 2
|
|
165
181
|
# Determine whether to recurse into subdirectories.
|
|
166
|
-
bool_recursive = not
|
|
182
|
+
bool_recursive = not parsed_options.no_recursive
|
|
167
183
|
# Run all checkers on the resolved paths.
|
|
168
184
|
report_result = run(list_resolved, bool_recursive=bool_recursive)
|
|
169
185
|
# Apply category filter if one was specified.
|
|
170
|
-
if
|
|
186
|
+
if parsed_options.category:
|
|
171
187
|
# Filter violations to only the requested category.
|
|
172
188
|
report_result.list_violations = [
|
|
173
189
|
# Iterate over each violation to check against the filter.
|
|
174
|
-
|
|
190
|
+
violation_item for violation_item in report_result.list_violations
|
|
175
191
|
# Keep only violations matching the requested category filter.
|
|
176
|
-
if
|
|
192
|
+
if violation_item.string_category == parsed_options.category
|
|
177
193
|
# Close the filtered list comprehension.
|
|
178
194
|
]
|
|
179
195
|
# Print the summary line to stdout.
|
|
180
196
|
print(report_result.summary())
|
|
181
197
|
# Print individual violations unless quiet mode is active.
|
|
182
|
-
if report_result.list_violations and not
|
|
198
|
+
if report_result.list_violations and not parsed_options.quiet:
|
|
183
199
|
# Add a blank line before the violation listing.
|
|
184
200
|
print()
|
|
185
201
|
# Print the formatted violation details.
|
|
@@ -21,16 +21,16 @@ MAINTAINER :
|
|
|
21
21
|
|
|
22
22
|
PROJECT CREATE DATE : 2026-06-17
|
|
23
23
|
|
|
24
|
-
PROJECT VERSION DATE : 2026-07-
|
|
24
|
+
PROJECT VERSION DATE : 2026-07-06
|
|
25
25
|
|
|
26
|
-
PROJECT VERSION : 0.4.
|
|
26
|
+
PROJECT VERSION : 0.4.2
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
FILE CREATE DATE : 2026-06-17
|
|
30
30
|
|
|
31
|
-
FILE VERSION DATE : 2026-07-
|
|
31
|
+
FILE VERSION DATE : 2026-07-06
|
|
32
32
|
|
|
33
|
-
FILE VERSION : 0.4.
|
|
33
|
+
FILE VERSION : 0.4.1
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
STATUS : Stable
|
|
@@ -75,38 +75,26 @@ from typing import List, Set, cast
|
|
|
75
75
|
|
|
76
76
|
from .reporter import Violation
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
comment_exempt = frozenset({
|
|
80
|
-
# Include the standard import statement keyword.
|
|
81
|
-
"import",
|
|
82
|
-
# Include the from-import statement keyword.
|
|
83
|
-
"from",
|
|
84
|
-
# Include the class definition keyword.
|
|
85
|
-
"class",
|
|
86
|
-
# Include the function definition keyword.
|
|
87
|
-
"def",
|
|
88
|
-
# Close the exempt keywords frozenset literal.
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
# Define weak comment starter patterns that merely restate code rather than explain intent.
|
|
92
|
-
weak_patterns = (
|
|
93
|
-
# Detect "Check if ..." and "Check whether ..." patterns that restate conditions.
|
|
94
|
-
r'^Check\s+if\b',
|
|
95
|
-
# Detect "Check whether ..." variant.
|
|
96
|
-
r'^Check\s+whether\b',
|
|
97
|
-
# Close the weak comment pattern tuple.
|
|
98
|
-
)
|
|
78
|
+
from .configuration import comment_exempt, weak_patterns
|
|
99
79
|
|
|
100
80
|
# Compile the encoding declaration regex for detecting coding declarations.
|
|
101
81
|
regex_encoding = re.compile(
|
|
102
82
|
# Match the standard PEP 263 encoding declaration format.
|
|
103
83
|
r'^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)',
|
|
104
|
-
# Close the regex compilation call.
|
|
105
84
|
)
|
|
106
85
|
|
|
107
86
|
|
|
108
|
-
def
|
|
109
|
-
"""Tokenize source
|
|
87
|
+
def _init_tokenize_code_function_(string_source: str) -> List[tokenize.TokenInfo]:
|
|
88
|
+
"""Tokenize a source string into a list of token information objects.
|
|
89
|
+
|
|
90
|
+
Wraps tokenize.generate_tokens with a StringIO buffer to convert
|
|
91
|
+
the source string into an iterable token stream for inspection.
|
|
92
|
+
|
|
93
|
+
:param string_source: Complete Python source code as a single string.
|
|
94
|
+
:type string_source: str
|
|
95
|
+
:return: A flat list of token information tuples from the tokenizer.
|
|
96
|
+
:rtype: List[tokenize.TokenInfo]
|
|
97
|
+
"""
|
|
110
98
|
# Generate tokens from the source string using a StringIO buffer.
|
|
111
99
|
return list(tokenize.generate_tokens(io.StringIO(string_source).readline))
|
|
112
100
|
|
|
@@ -198,7 +186,7 @@ class CommentChecker:
|
|
|
198
186
|
# Attempt to tokenize the source; skip if tokenization fails.
|
|
199
187
|
try:
|
|
200
188
|
# Tokenize the full source code into a list of token objects.
|
|
201
|
-
list_tokens =
|
|
189
|
+
list_tokens = _init_tokenize_code_function_(self.string_source)
|
|
202
190
|
# Return early if the source cannot be tokenized.
|
|
203
191
|
except tokenize.TokenError:
|
|
204
192
|
# Exit the method early when tokenization fails.
|
|
@@ -371,7 +359,7 @@ class CommentChecker:
|
|
|
371
359
|
# Attempt to tokenize the source; skip if tokenization fails.
|
|
372
360
|
try:
|
|
373
361
|
# Tokenize the full source code for comment format checking.
|
|
374
|
-
list_tokens =
|
|
362
|
+
list_tokens = _init_tokenize_code_function_(self.string_source)
|
|
375
363
|
# Return early if the source cannot be tokenized.
|
|
376
364
|
except tokenize.TokenError:
|
|
377
365
|
# Exit the method early when tokenization fails.
|
|
@@ -526,7 +514,7 @@ class CommentChecker:
|
|
|
526
514
|
# Attempt to tokenize the source; skip if tokenization fails.
|
|
527
515
|
try:
|
|
528
516
|
# Tokenize the full source code for symbol-line comment detection.
|
|
529
|
-
list_tokens =
|
|
517
|
+
list_tokens = _init_tokenize_code_function_(self.string_source)
|
|
530
518
|
# Return early if the source cannot be tokenized.
|
|
531
519
|
except tokenize.TokenError:
|
|
532
520
|
# Exit the method early when tokenization fails.
|
|
@@ -699,7 +687,7 @@ class CommentChecker:
|
|
|
699
687
|
# Attempt to tokenize the source; skip if tokenization fails.
|
|
700
688
|
try:
|
|
701
689
|
# Tokenize the full source code for weak comment detection.
|
|
702
|
-
list_tokens =
|
|
690
|
+
list_tokens = _init_tokenize_code_function_(self.string_source)
|
|
703
691
|
# Return early if the source cannot be tokenized.
|
|
704
692
|
except tokenize.TokenError:
|
|
705
693
|
# Exit the method early when tokenization fails.
|
|
@@ -759,7 +747,7 @@ class CommentChecker:
|
|
|
759
747
|
# Attempt to tokenize the source; skip if tokenization fails.
|
|
760
748
|
try:
|
|
761
749
|
# Tokenize the full source code for comment language detection.
|
|
762
|
-
list_tokens =
|
|
750
|
+
list_tokens = _init_tokenize_code_function_(self.string_source)
|
|
763
751
|
# Return early if the source cannot be tokenized.
|
|
764
752
|
except tokenize.TokenError:
|
|
765
753
|
# Exit the method early when tokenization fails.
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
THIS FILE IS CORE PART OF CLASPLINT BY MATT BELFAST BROWN.
|
|
4
|
+
|
|
5
|
+
===============================================================================
|
|
6
|
+
|
|
7
|
+
MODULE : CLASPLint.configuration
|
|
8
|
+
|
|
9
|
+
TYPE : Python Script
|
|
10
|
+
|
|
11
|
+
DESCRIPTION :
|
|
12
|
+
Lightweight YAML configuration loader for CLASP 3.2 word lists.
|
|
13
|
+
Parses configuration.yaml without external dependencies and exposes
|
|
14
|
+
all exemption sets, forbidden terms, and whitelist collections
|
|
15
|
+
as module-level constants for use by checker modules.
|
|
16
|
+
|
|
17
|
+
AUTHOR : Matt Belfast Brown
|
|
18
|
+
|
|
19
|
+
CONTACT : thedayofthedo@gmail.com
|
|
20
|
+
|
|
21
|
+
MAINTAINER :
|
|
22
|
+
Matt Belfast Brown (thedayofthedo@gmail.com)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
PROJECT CREATE DATE : 2026-06-17
|
|
26
|
+
|
|
27
|
+
PROJECT VERSION DATE : 2026-07-06
|
|
28
|
+
|
|
29
|
+
PROJECT VERSION : 0.4.2
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
FILE CREATE DATE : 2026-07-06
|
|
33
|
+
|
|
34
|
+
FILE VERSION DATE : 2026-07-06
|
|
35
|
+
|
|
36
|
+
FILE VERSION : 0.1.0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
STATUS : Stable
|
|
40
|
+
|
|
41
|
+
PYTHON : >=3.8
|
|
42
|
+
|
|
43
|
+
LICENSE : GPL-3.0-only
|
|
44
|
+
|
|
45
|
+
SPDX ID : GPL-3.0-only
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
USAGE :
|
|
49
|
+
from CLASPLint.config import common_words, forbidden_terms
|
|
50
|
+
|
|
51
|
+
===============================================================================
|
|
52
|
+
|
|
53
|
+
THIS PROGRAM IS LICENSED UNDER GPL-3.0-only LICENSE.
|
|
54
|
+
YOU SHOULD HAVE RECEIVED A COPY OF GPL-3.0-only LICENSE.
|
|
55
|
+
|
|
56
|
+
Copyright (C) 2026 Matt Belfast Brown.
|
|
57
|
+
|
|
58
|
+
Sort License:
|
|
59
|
+
|
|
60
|
+
CLASPLint is free software: you can redistribute it and/or modify
|
|
61
|
+
it under the terms of the GNU General Public License as published by
|
|
62
|
+
the Free Software Foundation, version 3 of the License.
|
|
63
|
+
|
|
64
|
+
CLASPLint is distributed in the hope that it will be useful,
|
|
65
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
66
|
+
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
67
|
+
GNU General Public License for more details.
|
|
68
|
+
|
|
69
|
+
You should have received a copy of the GNU General Public License
|
|
70
|
+
along with CLASPLint. If not, see <https://www.gnu.org/licenses/>.
|
|
71
|
+
"""
|
|
72
|
+
import os
|
|
73
|
+
from typing import Any, Dict, List, Union
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# Define the return type alias for the YAML value parser.
|
|
77
|
+
type_yaml = Union[str, List[str], Dict[str, str], bool, None]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _init_parse_value_function_(string_text: str) -> type_yaml:
|
|
81
|
+
"""Parse a YAML scalar or inline collection value from stripped text.
|
|
82
|
+
|
|
83
|
+
Handles flow sequences, flow mappings, quoted scalars, null literals,
|
|
84
|
+
boolean literals, and bare unquoted scalars.
|
|
85
|
+
|
|
86
|
+
:param string_text: The stripped string value from a YAML list item or mapping value.
|
|
87
|
+
:type string_text: str
|
|
88
|
+
:return: A parsed Python object representing the YAML value.
|
|
89
|
+
:rtype: Union[str, List[str], Dict[str, str], bool, None]
|
|
90
|
+
"""
|
|
91
|
+
# Detect and parse an inline flow-sequence value like [a, b, c].
|
|
92
|
+
if string_text.startswith("[") and string_text.endswith("]"):
|
|
93
|
+
# Strip the outer brackets to extract the inner comma-separated content.
|
|
94
|
+
string_inner = string_text[1:-1].strip()
|
|
95
|
+
# Build a list by splitting on commas and stripping quotes from each element.
|
|
96
|
+
list_elements = []
|
|
97
|
+
# Iterate over each comma-separated token within the brackets.
|
|
98
|
+
for string_element in string_inner.split(","):
|
|
99
|
+
# Strip whitespace from the current element token.
|
|
100
|
+
string_token = string_element.strip()
|
|
101
|
+
# Include non-empty tokens after quote removal.
|
|
102
|
+
if string_token:
|
|
103
|
+
# Strip single and double quotes from the token value.
|
|
104
|
+
list_elements.append(string_token.strip("'\""))
|
|
105
|
+
# Return the parsed list of cleaned element strings.
|
|
106
|
+
return list_elements
|
|
107
|
+
# Detect and parse an inline flow-mapping value like {key: val}.
|
|
108
|
+
if string_text.startswith("{") and string_text.endswith("}"):
|
|
109
|
+
# Strip the outer braces to extract the inner key-value pairs.
|
|
110
|
+
string_inner = string_text[1:-1].strip()
|
|
111
|
+
# Initialize an empty dictionary to collect the parsed key-value entries.
|
|
112
|
+
dict_output: Dict[str, str] = {}
|
|
113
|
+
# Split the mapping content on commas for each key-value pair.
|
|
114
|
+
for string_pair in string_inner.split(","):
|
|
115
|
+
# Require a colon separator to identify a valid key-value pair.
|
|
116
|
+
if ":" in string_pair:
|
|
117
|
+
# Split the pair on the first colon to separate key and value.
|
|
118
|
+
string_key, string_value = string_pair.split(":", 1)
|
|
119
|
+
# Strip whitespace and quotes from the key before storage.
|
|
120
|
+
string_cleankey = string_key.strip().strip("'\"")
|
|
121
|
+
# Strip whitespace and quotes from the value after the colon.
|
|
122
|
+
clean_value = string_value.strip().strip("'\"")
|
|
123
|
+
# Store the cleaned key-value entry in the output dictionary.
|
|
124
|
+
dict_output[string_cleankey] = clean_value
|
|
125
|
+
# Return the fully parsed inline mapping dictionary.
|
|
126
|
+
return dict_output
|
|
127
|
+
# Detect a single-quoted or double-quoted scalar value, verifying the wrapping pair match.
|
|
128
|
+
if (string_text.startswith("'") and string_text.endswith("'")) or (
|
|
129
|
+
# Also verify the double-quote pair variant for quoted scalar detection.
|
|
130
|
+
string_text.startswith('"') and string_text.endswith('"')
|
|
131
|
+
):
|
|
132
|
+
# Strip the surrounding quote characters and return the inner text.
|
|
133
|
+
return string_text[1:-1]
|
|
134
|
+
# Detect the YAML null literal keyword or tilde shorthand.
|
|
135
|
+
if string_text.lower() == "null" or string_text == "~":
|
|
136
|
+
# Return Python None to represent the absence of a value.
|
|
137
|
+
return None
|
|
138
|
+
# Detect the YAML boolean true literal keyword.
|
|
139
|
+
if string_text.lower() == "true":
|
|
140
|
+
# Return the Python boolean True constant.
|
|
141
|
+
return True
|
|
142
|
+
# Detect the YAML boolean false literal keyword.
|
|
143
|
+
if string_text.lower() == "false":
|
|
144
|
+
# Return the Python boolean False constant.
|
|
145
|
+
return False
|
|
146
|
+
# Return the bare unquoted scalar text as an ordinary string.
|
|
147
|
+
return string_text
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _init_load_yaml_function_(file_path: str) -> Dict[str, Any]:
|
|
151
|
+
"""Load a simplified YAML file and return a dictionary of parsed top-level keys.
|
|
152
|
+
|
|
153
|
+
Supports comments, block sequences, block mappings, and inline scalars.
|
|
154
|
+
Does not support anchors, aliases, tags, or multi-line strings.
|
|
155
|
+
|
|
156
|
+
:param file_path: Absolute or relative path to the YAML configuration file.
|
|
157
|
+
:type file_path: str
|
|
158
|
+
:return: Dictionary mapping top-level section keys to their parsed data values.
|
|
159
|
+
:rtype: Dict[str, Any]
|
|
160
|
+
"""
|
|
161
|
+
# Open the YAML file with UTF-8 encoding for reading.
|
|
162
|
+
with open(file_path, "r", encoding="utf-8") as file_handle:
|
|
163
|
+
# Read every line from the configuration file into memory.
|
|
164
|
+
list_lines = file_handle.readlines()
|
|
165
|
+
# Initialize the top-level dictionary to accumulate parsed section data.
|
|
166
|
+
dict_result: Dict[str, Any] = {}
|
|
167
|
+
# Track the name of the currently active top-level YAML section key.
|
|
168
|
+
current_key: str = ""
|
|
169
|
+
# Track the indentation depth of the current top-level section header.
|
|
170
|
+
current_indent: int = 0
|
|
171
|
+
# Buffer accumulated child entries for the currently active section.
|
|
172
|
+
list_buffer = []
|
|
173
|
+
# Track whether the current section contains a mapping or a sequence.
|
|
174
|
+
is_mapping: bool = False
|
|
175
|
+
# Iterate over each physical line in the file to parse the structure.
|
|
176
|
+
for string_line in list_lines:
|
|
177
|
+
# Strip the platform-specific trailing newline to obtain clean content.
|
|
178
|
+
line_raw = string_line.rstrip("\n").rstrip("\r")
|
|
179
|
+
# Skip lines that are empty or consist entirely of a YAML comment.
|
|
180
|
+
if not line_raw or line_raw.lstrip().startswith("#"):
|
|
181
|
+
# Move to the next line without processing this one.
|
|
182
|
+
continue
|
|
183
|
+
# Compute the leading whitespace indent for hierarchy level detection.
|
|
184
|
+
trim_line = line_raw.lstrip()
|
|
185
|
+
# Derive the indentation depth from the difference between raw and stripped length.
|
|
186
|
+
int_indent = len(line_raw) - len(trim_line)
|
|
187
|
+
# Detect a top-level key declaration ending with a colon at zero indent.
|
|
188
|
+
if int_indent == 0 and trim_line.endswith(":") and not trim_line.startswith("-"):
|
|
189
|
+
# Flush any previously buffered section data into the result dictionary.
|
|
190
|
+
if current_key and list_buffer:
|
|
191
|
+
# Distinguish between mapping and sequence buffer formats.
|
|
192
|
+
if is_mapping:
|
|
193
|
+
# Construct a dictionary from the accumulated key-value pair strings.
|
|
194
|
+
work_map: Dict[str, str] = {}
|
|
195
|
+
# Process each buffered entry that should contain a colon separator.
|
|
196
|
+
for each_one in list_buffer:
|
|
197
|
+
# Verify the entry contains a key-value separator.
|
|
198
|
+
if ":" in each_one:
|
|
199
|
+
# Split on the first colon to separate the key from the value.
|
|
200
|
+
text_key, text_value = each_one.split(":", 1)
|
|
201
|
+
# Store the cleaned key-value mapping entry.
|
|
202
|
+
work_map[text_key.strip()] = text_value.strip()
|
|
203
|
+
# Assign the constructed mapping dictionary to the result.
|
|
204
|
+
dict_result[current_key] = work_map
|
|
205
|
+
# Branch to handle sequence mode when the buffer contains list items.
|
|
206
|
+
else:
|
|
207
|
+
# Assign the accumulated sequence items as an immutable frozenset.
|
|
208
|
+
dict_result[current_key] = frozenset(list_buffer)
|
|
209
|
+
# Clear the buffer to prepare for the newly encountered section.
|
|
210
|
+
list_buffer = []
|
|
211
|
+
# Extract the new section key by removing the trailing colon.
|
|
212
|
+
current_key = trim_line[:-1].strip()
|
|
213
|
+
# Record the base indentation level for this section header.
|
|
214
|
+
current_indent = int_indent
|
|
215
|
+
# Default to treating the section as a sequence until a mapping entry appears.
|
|
216
|
+
is_mapping = False
|
|
217
|
+
# Skip further processing of this header line.
|
|
218
|
+
continue
|
|
219
|
+
# Detect a first-level list item introduced by a dash and space at section depth.
|
|
220
|
+
if int_indent > current_indent and trim_line.startswith("- "):
|
|
221
|
+
# Extract the raw value following the dash-space prefix.
|
|
222
|
+
value_text = trim_line[2:].strip()
|
|
223
|
+
# Determine whether the value contains a colon indicating an inline mapping entry.
|
|
224
|
+
if ":" in value_text and not value_text.startswith(("{", "[", "'", '"')):
|
|
225
|
+
# Switch the section mode to mapping since key-value syntax was detected.
|
|
226
|
+
is_mapping = True
|
|
227
|
+
# Append the raw key-value string to the buffer for later mapping construction.
|
|
228
|
+
list_buffer.append(value_text)
|
|
229
|
+
# Branch to handle a plain scalar value when the item is not a mapping entry.
|
|
230
|
+
else:
|
|
231
|
+
# Interpret the value as a plain scalar and parse it through the value parser.
|
|
232
|
+
out_data = _init_parse_value_function_(value_text)
|
|
233
|
+
# Buffer the parsed value, falling back to the raw string for unknown types.
|
|
234
|
+
list_buffer.append(out_data if out_data is not None else value_text)
|
|
235
|
+
# Skip further processing of this list item line.
|
|
236
|
+
continue
|
|
237
|
+
# Detect continuation lines at a deeper indent that do not carry a list dash.
|
|
238
|
+
if int_indent > current_indent and current_key:
|
|
239
|
+
# Strip surrounding whitespace from the continuation line content.
|
|
240
|
+
clean_text = trim_line.strip()
|
|
241
|
+
# Exclude continuation lines that are purely YAML comment markers.
|
|
242
|
+
if clean_text and not clean_text.startswith("#"):
|
|
243
|
+
# Determine whether this continuation line contains mapping-style colon syntax.
|
|
244
|
+
if ":" in clean_text and not clean_text.startswith(("{", "[", "'", '"')):
|
|
245
|
+
# Switch the section mode to mapping for colon-delimited entries.
|
|
246
|
+
is_mapping = True
|
|
247
|
+
# Append the continuation line content to the active section buffer.
|
|
248
|
+
list_buffer.append(clean_text)
|
|
249
|
+
# Flush the final buffered section into the result dictionary after the loop ends.
|
|
250
|
+
if current_key and list_buffer:
|
|
251
|
+
# Distinguish the final buffer type between mapping and sequence data.
|
|
252
|
+
if is_mapping:
|
|
253
|
+
# Build a dictionary from the remaining key-value pair strings.
|
|
254
|
+
work_map = {}
|
|
255
|
+
# Process each leftover buffered entry for colon-separated pairs.
|
|
256
|
+
for each_one in list_buffer:
|
|
257
|
+
# Confirm the entry still contains a valid key-value separator.
|
|
258
|
+
if ":" in each_one:
|
|
259
|
+
# Split on the first colon to extract key and value portions.
|
|
260
|
+
text_key, text_value = each_one.split(":", 1)
|
|
261
|
+
# Store the cleaned final mapping entry.
|
|
262
|
+
work_map[text_key.strip()] = text_value.strip()
|
|
263
|
+
# Assign the final constructed mapping to the result dictionary.
|
|
264
|
+
dict_result[current_key] = work_map
|
|
265
|
+
# Branch to collect the sequence items when the buffer is not a mapping.
|
|
266
|
+
else:
|
|
267
|
+
# Assign the final accumulated sequence as an immutable frozenset.
|
|
268
|
+
dict_result[current_key] = frozenset(list_buffer)
|
|
269
|
+
# Return the fully populated configuration data dictionary.
|
|
270
|
+
return dict_result
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# Resolve the absolute path to the configuration.yaml file next to this module.
|
|
274
|
+
yaml_path = os.path.join(str(os.path.dirname(__file__)), "configuration.yaml")
|
|
275
|
+
# Parse the YAML configuration file into a top-level dictionary of sets and mappings.
|
|
276
|
+
yaml_data = _init_load_yaml_function_(yaml_path)
|
|
277
|
+
|
|
278
|
+
# Expose each YAML section as a typed module-level constant for direct import by checker modules.
|
|
279
|
+
# Extract the set of permitted lowercase acronyms from the configuration data.
|
|
280
|
+
lower_acronyms: frozenset = yaml_data.get("lower_acronyms", frozenset())
|
|
281
|
+
# Extract the set of permitted uppercase acronyms from the configuration data.
|
|
282
|
+
upper_acronyms: frozenset = yaml_data.get("upper_acronyms", frozenset())
|
|
283
|
+
# Extract the mapping of forbidden abbreviations to their full word equivalents.
|
|
284
|
+
forbidden_terms: dict = yaml_data.get("forbidden_terms", {})
|
|
285
|
+
# Extract the set of allowed type-prefix words for variable name group1.
|
|
286
|
+
type_words: frozenset = yaml_data.get("type_words", frozenset())
|
|
287
|
+
# Extract the set of mandatory boolean prefixes for variable name group1.
|
|
288
|
+
bool_words: frozenset = yaml_data.get("bool_words", frozenset())
|
|
289
|
+
# Extract the set of overly generic verbs that trigger function name warnings.
|
|
290
|
+
verbs_vague: frozenset = yaml_data.get("verbs_vague", frozenset())
|
|
291
|
+
# Extract the set of variable names that bypass all naming checks.
|
|
292
|
+
names_exempt: frozenset = yaml_data.get("names_exempt", frozenset())
|
|
293
|
+
# Extract the set of compound names exempt from per-group abbreviation scanning.
|
|
294
|
+
compound_allow: frozenset = yaml_data.get("compound_allow", frozenset())
|
|
295
|
+
# Extract the set of common short English words that should not trigger the heuristic.
|
|
296
|
+
common_words: frozenset = yaml_data.get("common_words", frozenset())
|
|
297
|
+
# Extract the set of source code keywords that are exempt from preceding-comment rules.
|
|
298
|
+
comment_exempt: frozenset = yaml_data.get("comment_exempt", frozenset())
|
|
299
|
+
# Convert the weak comment regex pattern list into a tuple for re.compile compatibility.
|
|
300
|
+
weak_patterns: tuple = tuple(yaml_data.get("weak_patterns", frozenset()))
|
|
301
|
+
# Extract the set of parameter names not requiring Sphinx directives in method docstrings.
|
|
302
|
+
exempt_context: set = set(yaml_data.get("exempt_context", frozenset()))
|
|
303
|
+
# Extract the set of technical terms exempt from abbreviation checks within docstring prose.
|
|
304
|
+
tech_exemptions: set = set(yaml_data.get("tech_exemptions", frozenset()))
|
|
305
|
+
# Extract dict keys exempt from PascalCase enforcement for external system compatibility.
|
|
306
|
+
dictkey_exempt: frozenset = yaml_data.get("dictkey_exempt", frozenset())
|