CLASPLint 0.5.0__tar.gz → 0.5.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.
Files changed (28) hide show
  1. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/__init__.py +5 -5
  2. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/__main__.py +6 -2
  3. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/checker_base.py +2 -2
  4. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/comment_checker.py +2 -2
  5. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/configuration.py +2 -2
  6. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/configuration.yaml +39 -5
  7. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/dict_key_checker.py +7 -7
  8. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/docstring_checker.py +60 -6
  9. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/function_checker.py +10 -10
  10. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/log_checker.py +2 -2
  11. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/naming_utils.py +18 -6
  12. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/reporter.py +2 -2
  13. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/runner.py +2 -2
  14. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/try_except_checker.py +2 -2
  15. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint/variable_checker.py +51 -21
  16. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint.egg-info/PKG-INFO +4 -4
  17. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/PKG-INFO +4 -4
  18. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/README.md +3 -3
  19. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/pyproject.toml +1 -1
  20. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/setup.py +5 -5
  21. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint.egg-info/SOURCES.txt +0 -0
  22. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint.egg-info/dependency_links.txt +0 -0
  23. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint.egg-info/entry_points.txt +0 -0
  24. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint.egg-info/not-zip-safe +0 -0
  25. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/CLASPLint.egg-info/top_level.txt +0 -0
  26. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/LICENSE +0 -0
  27. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/MANIFEST.in +0 -0
  28. {CLASPLint-0.5.0 → CLASPLint-0.5.2}/setup.cfg +0 -0
@@ -22,16 +22,16 @@ MAINTAINER :
22
22
 
23
23
  PROJECT CREATE DATE : 2026-06-17
24
24
 
25
- PROJECT VERSION DATE : 2026-07-08
25
+ PROJECT VERSION DATE : 2026-07-11
26
26
 
27
- PROJECT VERSION : 0.5.0
27
+ PROJECT VERSION : 0.5.2
28
28
 
29
29
 
30
30
  FILE CREATE DATE : 2026-06-17
31
31
 
32
- FILE VERSION DATE : 2026-07-08
32
+ FILE VERSION DATE : 2026-07-11
33
33
 
34
- FILE VERSION : 0.5.0
34
+ FILE VERSION : 1.0.1
35
35
 
36
36
 
37
37
  STATUS : Stable
@@ -71,6 +71,6 @@ Sort License:
71
71
  """
72
72
 
73
73
  # Define the package version string.
74
- __version__ = "0.5.0"
74
+ __version__ = "0.5.2"
75
75
  # Expose the runner and reporter modules as the public API.
76
76
  __all__ = ["runner", "reporter"]
@@ -20,9 +20,9 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
@@ -159,6 +159,10 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
159
159
  :return: Exit code 0 when no violations are found, 1 otherwise.
160
160
  :rtype: int
161
161
  """
162
+ # Ensure stdout and stderr use UTF-8 encoding for cross-platform Chinese output.
163
+ sys.stdout.reconfigure(encoding='utf-8')
164
+ # Reconfigure the standard error stream to use UTF-8 encoding.
165
+ sys.stderr.reconfigure(encoding='utf-8')
162
166
  # Build and parse command-line arguments.
163
167
  command_parser = _init_build_parser_function_()
164
168
  # Parse the provided arguments or default to sys.argv.
@@ -22,9 +22,9 @@ MAINTAINER :
22
22
 
23
23
  PROJECT CREATE DATE : 2026-06-17
24
24
 
25
- PROJECT VERSION DATE : 2026-07-08
25
+ PROJECT VERSION DATE : 2026-07-11
26
26
 
27
- PROJECT VERSION : 0.5.0
27
+ PROJECT VERSION : 0.5.2
28
28
 
29
29
 
30
30
  FILE CREATE DATE : 2026-07-08
@@ -20,9 +20,9 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
@@ -23,9 +23,9 @@ MAINTAINER :
23
23
 
24
24
  PROJECT CREATE DATE : 2026-06-17
25
25
 
26
- PROJECT VERSION DATE : 2026-07-08
26
+ PROJECT VERSION DATE : 2026-07-11
27
27
 
28
- PROJECT VERSION : 0.5.0
28
+ PROJECT VERSION : 0.5.2
29
29
 
30
30
 
31
31
  FILE CREATE DATE : 2026-07-07
@@ -1,4 +1,4 @@
1
- # -*- coding: utf-8 -*-
1
+ # -*- coding: utf-8 -*-
2
2
  """
3
3
  THIS FILE IS CORE PART OF CLASPLINT BY MATT BELFAST BROWN.
4
4
 
@@ -24,16 +24,16 @@ MAINTAINER :
24
24
 
25
25
  PROJECT CREATE DATE : 2026-06-17
26
26
 
27
- PROJECT VERSION DATE : 2026-07-08
27
+ PROJECT VERSION DATE : 2026-07-11
28
28
 
29
- PROJECT VERSION : 0.5.0
29
+ PROJECT VERSION : 0.5.2
30
30
 
31
31
 
32
32
  FILE CREATE DATE : 2026-07-06
33
33
 
34
- FILE VERSION DATE : 2026-07-08
34
+ FILE VERSION DATE : 2026-07-11
35
35
 
36
- FILE VERSION : 1.0.0
36
+ FILE VERSION : 1.0.1
37
37
 
38
38
 
39
39
  STATUS : Stable
@@ -341,6 +341,40 @@ bool_words:
341
341
  - is
342
342
  # Require the has prefix to mark boolean possession-checking variables.
343
343
  - has
344
+ # Require the bool prefix to mark boolean type-prefixed variables.
345
+ - bool
346
+ # Require the should prefix to mark boolean recommendation variables.
347
+ - should
348
+ # Require the can prefix to mark boolean capability-checking variables.
349
+ - can
350
+ # Require the does prefix to mark boolean action-status variables.
351
+ - does
352
+ # Require the did prefix to mark boolean past-action variables.
353
+ - did
354
+ # Require the do prefix to mark boolean imperative variables.
355
+ - do
356
+ # Require the will prefix to mark boolean future-intent variables.
357
+ - will
358
+ # Require the was prefix to mark boolean past-state variables.
359
+ - was
360
+ # Require the were prefix to mark boolean past-plural variables.
361
+ - were
362
+ # Require the could prefix to mark boolean possibility variables.
363
+ - could
364
+ # Require the would prefix to mark boolean hypothetical variables.
365
+ - would
366
+ # Require the might prefix to mark boolean uncertainty variables.
367
+ - might
368
+ # Require the must prefix to mark boolean requirement variables.
369
+ - must
370
+ # Require the needs prefix to mark boolean need-indication variables.
371
+ - needs
372
+ # Require the contains prefix to mark boolean membership variables.
373
+ - contains
374
+ # Require the allows prefix to mark boolean permission variables.
375
+ - allows
376
+ # Require the supports prefix to mark boolean feature-check variables.
377
+ - supports
344
378
 
345
379
  # Vague verbs that trigger function name warnings when used at the start.
346
380
  verbs_vague:
@@ -20,16 +20,16 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
29
29
 
30
- FILE VERSION DATE : 2026-07-08
30
+ FILE VERSION DATE : 2026-07-11
31
31
 
32
- FILE VERSION : 1.0.0
32
+ FILE VERSION : 1.0.1
33
33
 
34
34
 
35
35
  STATUS : Stable
@@ -94,7 +94,7 @@ class DictKeyChecker(ast.NodeVisitor):
94
94
  Visit subscript nodes for potential dict key access in assignments.
95
95
 
96
96
  PRIVATE METHODS :
97
- _init_key_function_(node_key: ast.AST) -> None:
97
+ _init_validate_key_function_(node_key: ast.AST) -> None:
98
98
  Validate a string-constant dictionary key.
99
99
  _init_keyword_as_key_function_(node_keyword: ast.keyword) -> list:
100
100
  Validate a keyword argument name used as a dictionary key.
@@ -129,7 +129,7 @@ class DictKeyChecker(ast.NodeVisitor):
129
129
  # Collect violations found during AST traversal.
130
130
  self.list_violations: List[Violation] = []
131
131
 
132
- def _init_key_function_(self, node_key: ast.AST) -> None:
132
+ def _init_validate_key_function_(self, node_key: ast.AST) -> None:
133
133
  """
134
134
  Validate a single dictionary key literal.
135
135
 
@@ -197,7 +197,7 @@ class DictKeyChecker(ast.NodeVisitor):
197
197
  # Process non-None keys through the key validator.
198
198
  if node_key is not None:
199
199
  # Delegate to the key validation method for this dictionary key.
200
- self._init_key_function_(node_key)
200
+ self._init_validate_key_function_(node_key)
201
201
  # Continue visiting child nodes for nested dictionaries.
202
202
  self.generic_visit(ast_node)
203
203
 
@@ -20,16 +20,16 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
29
29
 
30
- FILE VERSION DATE : 2026-07-08
30
+ FILE VERSION DATE : 2026-07-11
31
31
 
32
- FILE VERSION : 1.0.0
32
+ FILE VERSION : 1.0.1
33
33
 
34
34
 
35
35
  STATUS : Stable
@@ -156,6 +156,8 @@ class DocstringChecker(ast.NodeVisitor):
156
156
  self.list_violations: List[Violation] = []
157
157
  # Track the current class name for contextual messages.
158
158
  self.string_currentclass: str = ""
159
+ # Track whether the current class inherits from ast.NodeVisitor for visit_* exemption.
160
+ self.is_astvisitor: bool = False
159
161
 
160
162
  def _init_add_violation_function_(self, ast_node: ast.AST, string_message: str) -> None:
161
163
  """
@@ -273,10 +275,16 @@ class DocstringChecker(ast.NodeVisitor):
273
275
  string_previous = self.string_currentclass
274
276
  # Set the current class name for method context messages.
275
277
  self.string_currentclass = ast_node.name
278
+ # Save the previous visitor flag before entering the new class.
279
+ was_visitor = self.is_astvisitor
280
+ # Determine whether this class inherits from ast.NodeVisitor for visit_* exemption.
281
+ self.is_astvisitor = self._init_detect_visitor_function_(ast_node)
276
282
  # Visit child nodes within the class body to check methods.
277
283
  self.generic_visit(ast_node)
278
284
  # Restore the previous class context after leaving the class.
279
285
  self.string_currentclass = string_previous
286
+ # Restore the previous visitor flag after leaving the class.
287
+ self.is_astvisitor = was_visitor
280
288
 
281
289
  def visit_FunctionDef(self, ast_node: Union[ast.FunctionDef, ast.AsyncFunctionDef]) -> None:
282
290
  """
@@ -319,8 +327,14 @@ class DocstringChecker(ast.NodeVisitor):
319
327
  return
320
328
  # Perform Sphinx format validation only for class methods.
321
329
  if bool_ismethod:
322
- # Validate the method docstring against the Sphinx directive format.
323
- self._init_check_format_function_(ast_node, docstring_text, display_name)
330
+ # Skip Sphinx format checks for visit_* methods in ast.NodeVisitor subclasses.
331
+ if self.is_astvisitor and ast_node.name.startswith("visit_"):
332
+ # Exempt NodeVisitor callback methods per CLASP Stage 3.3 Section 6.4.4.
333
+ pass
334
+ # Sphinx format checks apply to non-visit methods only.
335
+ else:
336
+ # Validate the method docstring against the Sphinx directive format.
337
+ self._init_check_format_function_(ast_node, docstring_text, display_name)
324
338
  # Validate docstring text quality for all functions and methods.
325
339
  self._init_chk_doc_qual_function_(ast_node, docstring_text, display_name)
326
340
  # Continue visiting the function body for nested definitions.
@@ -341,6 +355,46 @@ class DocstringChecker(ast.NodeVisitor):
341
355
  # Delegate to the standard function definition visitor.
342
356
  self.visit_FunctionDef(ast_node)
343
357
 
358
+ @staticmethod
359
+ def _init_detect_visitor_function_(class_node: ast.ClassDef) -> bool:
360
+ """
361
+ Determine whether the class definition inherits from ast.NodeVisitor.
362
+
363
+ Inspects each base class of the given ClassDef node and checks whether any
364
+ base matches the ast.NodeVisitor attribute chain. Returns True immediately
365
+ upon finding a match, or False after exhausting all bases.
366
+
367
+ The parameters are as follows:
368
+
369
+ :param class_node: The ClassDef AST node whose base classes are inspected.
370
+ :type class_node: ast.ClassDef
371
+ :return: True if any base class is ast.NodeVisitor, False otherwise.
372
+ :rtype: bool
373
+ """
374
+ # Iterate over each base class in the class definition.
375
+ for node_base in class_node.bases:
376
+ # Check for direct ast.NodeVisitor base class reference.
377
+ if isinstance(node_base, ast.Attribute):
378
+ # Verify the attribute chain matches ast.NodeVisitor.
379
+ if (
380
+ # Check that the value is an ast Name node.
381
+ isinstance(node_base.value, ast.Name)
382
+ # Match the module name ast.
383
+ and node_base.value.id == "ast"
384
+ # Match the class name NodeVisitor.
385
+ and node_base.attr == "NodeVisitor"
386
+ ):
387
+ # Confirm that the class inherits from ast.NodeVisitor.
388
+ return True
389
+ # Check for known NodeVisitor subclass as base class.
390
+ if isinstance(node_base, ast.Name):
391
+ # Detect known NodeVisitor subclasses used in this project.
392
+ if node_base.id == "CheckerBase":
393
+ # Confirm transitively inheriting from ast.NodeVisitor.
394
+ return True
395
+ # No ast.NodeVisitor base class was found in the inheritance chain.
396
+ return False
397
+
344
398
  def _init_check_format_function_(
345
399
  # Accept the function definition node for signature analysis.
346
400
  self, ast_node: Union[ast.FunctionDef, ast.AsyncFunctionDef],
@@ -20,16 +20,16 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
29
29
 
30
- FILE VERSION DATE : 2026-07-08
30
+ FILE VERSION DATE : 2026-07-11
31
31
 
32
- FILE VERSION : 1.0.0
32
+ FILE VERSION : 1.0.1
33
33
 
34
34
 
35
35
  STATUS : Stable
@@ -86,7 +86,7 @@ class FunctionChecker(CheckerBase):
86
86
  source_lines (list): Source lines for contextual messages.
87
87
  list_violations (list): Collected naming violations.
88
88
  string_currentclass (str): Current class context for method detection.
89
- bool_isastvisitor (bool): Whether current class inherits ast.NodeVisitor.
89
+ is_astvisitor (bool): Whether current class inherits ast.NodeVisitor.
90
90
 
91
91
  PUBLIC METHODS :
92
92
  visit_ClassDef(class_node: ast.ClassDef) -> None:
@@ -130,7 +130,7 @@ class FunctionChecker(CheckerBase):
130
130
  # Track the current class context for method detection.
131
131
  self.string_currentclass: str = ""
132
132
  # Track whether the current class inherits from ast.NodeVisitor.
133
- self.bool_isastvisitor: bool = False
133
+ self.is_astvisitor: bool = False
134
134
 
135
135
  def _init_add_violations_function_(
136
136
  # Accept the violation category for grouping in the report.
@@ -180,17 +180,17 @@ class FunctionChecker(CheckerBase):
180
180
  # Save the previous class context before entering the new class.
181
181
  string_previous = self.string_currentclass
182
182
  # Save the previous visitor flag before entering the new class.
183
- was_visitor = self.bool_isastvisitor
183
+ was_visitor = self.is_astvisitor
184
184
  # Set the current class context for method detection.
185
185
  self.string_currentclass = class_node.name
186
186
  # Determine whether this class inherits from ast.NodeVisitor for visit_* exemption.
187
- self.bool_isastvisitor = self._init_detect_visitor_function_(class_node)
187
+ self.is_astvisitor = self._init_detect_visitor_function_(class_node)
188
188
  # Visit child nodes within the class body.
189
189
  self.generic_visit(class_node)
190
190
  # Restore the previous class context after leaving the class.
191
191
  self.string_currentclass = string_previous
192
192
  # Restore the previous visitor flag after leaving the class.
193
- self.bool_isastvisitor = was_visitor
193
+ self.is_astvisitor = was_visitor
194
194
 
195
195
  def visit_FunctionDef(self, function_node: Union[ast.FunctionDef, ast.AsyncFunctionDef]) -> None:
196
196
  """
@@ -214,7 +214,7 @@ class FunctionChecker(CheckerBase):
214
214
  # Indicate whether this is a method or a module-level function.
215
215
  is_method=bool_ismethod,
216
216
  # Pass the AST visitor flag for targeted visit_* exemption.
217
- is_astvisitor=self.bool_isastvisitor,
217
+ is_astvisitor=self.is_astvisitor,
218
218
  )
219
219
  # Use the "function" category for all function and method violations.
220
220
  string_category = "function"
@@ -20,9 +20,9 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
@@ -20,16 +20,16 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
29
29
 
30
- FILE VERSION DATE : 2026-07-08
30
+ FILE VERSION DATE : 2026-07-11
31
31
 
32
- FILE VERSION : 1.0.0
32
+ FILE VERSION : 1.0.1
33
33
 
34
34
 
35
35
  STATUS : Stable
@@ -489,8 +489,20 @@ def is_private_method_format(string_name: str) -> bool:
489
489
  :return: True when the name matches the private method format pattern.
490
490
  :rtype: bool
491
491
  """
492
- # Use regex to match the required _init_..._function_ private method format.
493
- return bool(re.match(r'^_init_[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*_function_$', string_name))
492
+ # Match the _init_..._function_ pattern with fully spelled lowercase word groups.
493
+ match_result = re.match(r'^_init_([a-z]+(_[a-z]+)*)_function_$', string_name)
494
+ # Reject names that do not match the basic private method pattern.
495
+ if not match_result:
496
+ # Exit early when the name structure does not match _init_..._function_ format.
497
+ return False
498
+ # Extract the descriptor portion between _init_ and _function_.
499
+ string_descriptor = match_result.group(1)
500
+ # Split the descriptor into individual word segments by underscore.
501
+ list_words = string_descriptor.split('_')
502
+ # Count the number of fully spelled words in the descriptor.
503
+ int_wordcount = len(list_words)
504
+ # Enforce the 2-to-8 word range per CLASP Stage 3.3 Section 4.3.6.
505
+ return 2 <= int_wordcount <= 8
494
506
 
495
507
 
496
508
  def validate_variable_name(string_name: str) -> list:
@@ -20,9 +20,9 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
@@ -20,9 +20,9 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
@@ -21,9 +21,9 @@ MAINTAINER :
21
21
 
22
22
  PROJECT CREATE DATE : 2026-06-17
23
23
 
24
- PROJECT VERSION DATE : 2026-07-08
24
+ PROJECT VERSION DATE : 2026-07-11
25
25
 
26
- PROJECT VERSION : 0.5.0
26
+ PROJECT VERSION : 0.5.2
27
27
 
28
28
 
29
29
  FILE CREATE DATE : 2026-07-07
@@ -20,16 +20,16 @@ MAINTAINER :
20
20
 
21
21
  PROJECT CREATE DATE : 2026-06-17
22
22
 
23
- PROJECT VERSION DATE : 2026-07-08
23
+ PROJECT VERSION DATE : 2026-07-11
24
24
 
25
- PROJECT VERSION : 0.5.0
25
+ PROJECT VERSION : 0.5.2
26
26
 
27
27
 
28
28
  FILE CREATE DATE : 2026-06-17
29
29
 
30
- FILE VERSION DATE : 2026-07-08
30
+ FILE VERSION DATE : 2026-07-11
31
31
 
32
- FILE VERSION : 1.0.0
32
+ FILE VERSION : 1.0.2
33
33
 
34
34
 
35
35
  STATUS : Stable
@@ -352,16 +352,24 @@ class VariableChecker(ast.NodeVisitor):
352
352
  :param ast_node: The assignment AST node whose targets contain variable names.
353
353
  :type ast_node: ast.Assign
354
354
  """
355
- # Detect module-level ALL_CAPS assignments as constant naming violations.
355
+ # Detect ALL_CAPS assignments as constant naming violations.
356
356
  for target_node in ast_node.targets:
357
+ # Track the variable name string to validate, regardless of node type.
358
+ target_name = ""
357
359
  # Check simple Name targets for ALL_CAPS pattern suggesting a constant.
358
360
  if isinstance(target_node, ast.Name):
359
- # An all-uppercase name with underscores is the traditional Python constant pattern.
361
+ # Extract the identifier from the Name node.
360
362
  target_name = target_node.id
361
- # Exempt names in the check-skipping set.
362
- if target_name not in names_exempt:
363
- # Detect any uppercase letter in the variable name.
364
- if target_name != target_name.lower():
363
+ # Check attribute targets only for self or cls instance variables.
364
+ elif isinstance(target_node, ast.Attribute):
365
+ # Only extract the attribute name when the object is self or cls.
366
+ if isinstance(target_node.value, ast.Name) and target_node.value.id in ('self', 'cls'):
367
+ # Extract the attribute name from the Attribute node.
368
+ target_name = target_node.attr
369
+ # Validate the extracted name when it is not exempt from checks.
370
+ if target_name and target_name not in names_exempt:
371
+ # Detect any uppercase letter in the variable name.
372
+ if target_name != target_name.lower():
365
373
  # Build a unique key to prevent duplicate reports.
366
374
  int_lineno = getattr(ast_node, 'lineno', 0)
367
375
  # Guard against nodes that lack a reliable line number.
@@ -417,10 +425,22 @@ class VariableChecker(ast.NodeVisitor):
417
425
  :param ast_node: The assignment AST node to inspect for boolean literal values.
418
426
  :type ast_node: ast.Assign
419
427
  """
420
- # Only check simple Name targets, not unpacking patterns.
428
+ # Check Name and Attribute targets for boolean literal assignments.
421
429
  for target_node in ast_node.targets:
422
- # Skip non-Name targets and exempt names.
423
- if not isinstance(target_node, ast.Name) or target_node.id in names_exempt:
430
+ # Track the variable name regardless of target node type.
431
+ target_name = ""
432
+ # Extract the name from simple Name targets.
433
+ if isinstance(target_node, ast.Name):
434
+ # Retrieve the identifier from the Name node.
435
+ target_name = target_node.id
436
+ # Extract the attribute name only for self.xxx or cls.xxx Attribute targets.
437
+ elif isinstance(target_node, ast.Attribute):
438
+ # Only retrieve the attribute name when the object is self or cls.
439
+ if isinstance(target_node.value, ast.Name) and target_node.value.id in ('self', 'cls'):
440
+ # Retrieve the attribute name portion from the Attribute node.
441
+ target_name = target_node.attr
442
+ # Skip when no valid name was extracted or the name is exempt.
443
+ if not target_name or target_name in names_exempt:
424
444
  # Proceed to the next target.
425
445
  continue
426
446
  # Detect boolean literal assignments for prefix verification.
@@ -431,8 +451,6 @@ class VariableChecker(ast.NodeVisitor):
431
451
  if ast_node.value.value not in (True, False):
432
452
  # Skip non-boolean constants.
433
453
  continue
434
- # Extract the variable name for inspection.
435
- target_name = target_node.id
436
454
  # Extract the first underscore-separated group for prefix detection.
437
455
  list_groups = target_name.split("_")
438
456
  # Skip variables that already use the mandatory boolean prefix.
@@ -491,10 +509,20 @@ class VariableChecker(ast.NodeVisitor):
491
509
  """
492
510
  # Check that bool-annotated variables use the mandatory boolean prefix.
493
511
  if isinstance(ast_node.annotation, ast.Name) and ast_node.annotation.id == "bool":
494
- # Only apply the check to simple Name targets, not unpacking patterns.
495
- if isinstance(ast_node.target, ast.Name) and ast_node.target.id not in names_exempt:
496
- # Split to inspect whether group1 is a recognized boolean prefix.
512
+ # Track the variable name regardless of target node type.
513
+ target_name = ""
514
+ # Extract the name from simple Name targets.
515
+ if isinstance(ast_node.target, ast.Name):
516
+ # Retrieve the variable name from the Name node.
497
517
  target_name = ast_node.target.id
518
+ # Extract the attribute name only for self.xxx or cls.xxx Attribute targets.
519
+ elif isinstance(ast_node.target, ast.Attribute):
520
+ # Only retrieve the attribute name when the object is self or cls.
521
+ if isinstance(ast_node.target.value, ast.Name) and ast_node.target.value.id in ('self', 'cls'):
522
+ # Retrieve the attribute name portion from the Attribute node.
523
+ target_name = ast_node.target.attr
524
+ # Validate the bool prefix when a name was extracted and is not exempt.
525
+ if target_name and target_name not in names_exempt:
498
526
  # Extract the first underscore-separated group.
499
527
  list_groups = target_name.split("_")
500
528
  # Flag bool-annotated variables missing is_ or has_ prefix.
@@ -707,10 +735,12 @@ class VariableChecker(ast.NodeVisitor):
707
735
  elif isinstance(target, ast.Starred):
708
736
  # Recursively walk the value inside the starred expression.
709
737
  self._init_walk_target_function_(target.value)
710
- # Skip attribute assignments (obj.attr = ...) as these are not variable definitions.
738
+ # Validate instance variable names only when assigned via self.attr or cls.attr.
711
739
  elif isinstance(target, ast.Attribute):
712
- # Take no action for attribute assignment targets.
713
- pass
740
+ # Only validate attribute names on self or cls instances.
741
+ if isinstance(target.value, ast.Name) and target.value.id in ('self', 'cls'):
742
+ # Extract the attribute name part beyond the dot for validation.
743
+ self._init_check_name_function_(target.attr, target)
714
744
  # Skip subscript assignments (obj[key] = ...) as these are not variable definitions.
715
745
  elif isinstance(target, ast.Subscript):
716
746
  # Take no action for subscript assignment targets.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: CLASPLint
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: CLASP Stage 3.3 / PEP 2606 Static Analysis Tool — enforces naming and comment conventions beyond PEP 8.
5
5
  Author: Matt Belfast Brown
6
6
  Author-email: Matt Belfast Brown <thedayofthedo@gmail.com>
@@ -27,11 +27,11 @@ Requires-Python: >=3.8
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
 
30
- # CLASPLint
30
+ # CLASPLint
31
31
 
32
32
  [![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://www.python.org/)
33
33
  [![License](https://img.shields.io/badge/license-GPLv3-green)](./LICENSE)
34
- [![PyPI](https://img.shields.io/badge/pypi-v0.5.0-orange)](https://pypi.org/project/CLASPLint/)
34
+ [![PyPI](https://img.shields.io/badge/pypi-v0.5.2-orange)](https://pypi.org/project/CLASPLint/)
35
35
 
36
36
  > CLASP Stage 3.3 / PEP 2606 static analysis tool. Enforces naming and comment conventions beyond PEP 8 —
37
37
  > checks variables, dictionary keys, functions, classes, comments, and log messages for standards
@@ -210,7 +210,7 @@ CLASPLint supports **Python 3.8 through 3.14**. The minimum version is 3.8 due t
210
210
 
211
211
  [![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://www.python.org/)
212
212
  [![License](https://img.shields.io/badge/license-GPLv3-green)](./LICENSE)
213
- [![PyPI](https://img.shields.io/badge/pypi-v0.5.0-orange)](https://pypi.org/project/CLASPLint/)
213
+ [![PyPI](https://img.shields.io/badge/pypi-v0.5.2-orange)](https://pypi.org/project/CLASPLint/)
214
214
 
215
215
  > **CLASP Stage 3.3 / PEP 2606** 静态分析工具。在 PEP 8 **之上**强制执行命名与注释规范 ——
216
216
  > 检查变量、字典键、函数、类、注释和日志消息是否符合标准。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: CLASPLint
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: CLASP Stage 3.3 / PEP 2606 Static Analysis Tool — enforces naming and comment conventions beyond PEP 8.
5
5
  Author: Matt Belfast Brown
6
6
  Author-email: Matt Belfast Brown <thedayofthedo@gmail.com>
@@ -27,11 +27,11 @@ Requires-Python: >=3.8
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
 
30
- # CLASPLint
30
+ # CLASPLint
31
31
 
32
32
  [![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://www.python.org/)
33
33
  [![License](https://img.shields.io/badge/license-GPLv3-green)](./LICENSE)
34
- [![PyPI](https://img.shields.io/badge/pypi-v0.5.0-orange)](https://pypi.org/project/CLASPLint/)
34
+ [![PyPI](https://img.shields.io/badge/pypi-v0.5.2-orange)](https://pypi.org/project/CLASPLint/)
35
35
 
36
36
  > CLASP Stage 3.3 / PEP 2606 static analysis tool. Enforces naming and comment conventions beyond PEP 8 —
37
37
  > checks variables, dictionary keys, functions, classes, comments, and log messages for standards
@@ -210,7 +210,7 @@ CLASPLint supports **Python 3.8 through 3.14**. The minimum version is 3.8 due t
210
210
 
211
211
  [![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://www.python.org/)
212
212
  [![License](https://img.shields.io/badge/license-GPLv3-green)](./LICENSE)
213
- [![PyPI](https://img.shields.io/badge/pypi-v0.5.0-orange)](https://pypi.org/project/CLASPLint/)
213
+ [![PyPI](https://img.shields.io/badge/pypi-v0.5.2-orange)](https://pypi.org/project/CLASPLint/)
214
214
 
215
215
  > **CLASP Stage 3.3 / PEP 2606** 静态分析工具。在 PEP 8 **之上**强制执行命名与注释规范 ——
216
216
  > 检查变量、字典键、函数、类、注释和日志消息是否符合标准。
@@ -1,8 +1,8 @@
1
- # CLASPLint
1
+ # CLASPLint
2
2
 
3
3
  [![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://www.python.org/)
4
4
  [![License](https://img.shields.io/badge/license-GPLv3-green)](./LICENSE)
5
- [![PyPI](https://img.shields.io/badge/pypi-v0.5.0-orange)](https://pypi.org/project/CLASPLint/)
5
+ [![PyPI](https://img.shields.io/badge/pypi-v0.5.2-orange)](https://pypi.org/project/CLASPLint/)
6
6
 
7
7
  > CLASP Stage 3.3 / PEP 2606 static analysis tool. Enforces naming and comment conventions beyond PEP 8 —
8
8
  > checks variables, dictionary keys, functions, classes, comments, and log messages for standards
@@ -181,7 +181,7 @@ CLASPLint supports **Python 3.8 through 3.14**. The minimum version is 3.8 due t
181
181
 
182
182
  [![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://www.python.org/)
183
183
  [![License](https://img.shields.io/badge/license-GPLv3-green)](./LICENSE)
184
- [![PyPI](https://img.shields.io/badge/pypi-v0.5.0-orange)](https://pypi.org/project/CLASPLint/)
184
+ [![PyPI](https://img.shields.io/badge/pypi-v0.5.2-orange)](https://pypi.org/project/CLASPLint/)
185
185
 
186
186
  > **CLASP Stage 3.3 / PEP 2606** 静态分析工具。在 PEP 8 **之上**强制执行命名与注释规范 ——
187
187
  > 检查变量、字典键、函数、类、注释和日志消息是否符合标准。
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "CLASPLint"
7
- version = "0.5.0"
7
+ version = "0.5.2"
8
8
  description = "CLASP Stage 3.3 / PEP 2606 Static Analysis Tool — enforces naming and comment conventions beyond PEP 8."
9
9
  readme = "README.md"
10
10
  license = {text = "GPL-3.0-only"}
@@ -23,16 +23,16 @@ MAINTAINER :
23
23
 
24
24
  PROJECT CREATE DATE : 2026-06-17
25
25
 
26
- PROJECT VERSION DATE : 2026-07-08
26
+ PROJECT VERSION DATE : 2026-07-11
27
27
 
28
- PROJECT VERSION : 0.5.0
28
+ PROJECT VERSION : 0.5.2
29
29
 
30
30
 
31
31
  FILE CREATE DATE : 2026-06-17
32
32
 
33
- FILE VERSION DATE : 2026-07-08
33
+ FILE VERSION DATE : 2026-07-11
34
34
 
35
- FILE VERSION : 0.5.0
35
+ FILE VERSION : 1.0.1
36
36
 
37
37
 
38
38
  STATUS : Stable
@@ -75,7 +75,7 @@ setup(
75
75
  # Declare the package name used for PyPI registration and pip install.
76
76
  name="CLASPLint",
77
77
  # Declare the semantic version following major.minor.patch convention.
78
- version="0.5.0",
78
+ version="0.5.2",
79
79
 
80
80
  # Provide a brief description of the tool for PyPI and help text.
81
81
  description="CLASP Stage 3.3 / PEP 2606 Static Analysis Tool",
File without changes
File without changes
File without changes