thailint 0.11.0__py3-none-any.whl → 0.13.0__py3-none-any.whl
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.
- src/analyzers/__init__.py +4 -3
- src/analyzers/ast_utils.py +54 -0
- src/analyzers/typescript_base.py +4 -0
- src/cli/__init__.py +3 -0
- src/cli/config.py +12 -12
- src/cli/config_merge.py +241 -0
- src/cli/linters/__init__.py +3 -0
- src/cli/linters/code_patterns.py +113 -5
- src/cli/linters/code_smells.py +118 -7
- src/cli/linters/documentation.py +3 -0
- src/cli/linters/structure.py +3 -0
- src/cli/linters/structure_quality.py +3 -0
- src/cli/utils.py +29 -9
- src/cli_main.py +3 -0
- src/config.py +2 -1
- src/core/base.py +3 -2
- src/core/cli_utils.py +3 -1
- src/core/config_parser.py +5 -2
- src/core/constants.py +54 -0
- src/core/linter_utils.py +4 -0
- src/core/rule_discovery.py +5 -1
- src/core/violation_builder.py +3 -0
- src/linter_config/directive_markers.py +109 -0
- src/linter_config/ignore.py +225 -383
- src/linter_config/pattern_utils.py +65 -0
- src/linter_config/rule_matcher.py +89 -0
- src/linters/collection_pipeline/any_all_analyzer.py +281 -0
- src/linters/collection_pipeline/ast_utils.py +40 -0
- src/linters/collection_pipeline/config.py +12 -0
- src/linters/collection_pipeline/continue_analyzer.py +2 -8
- src/linters/collection_pipeline/detector.py +262 -32
- src/linters/collection_pipeline/filter_map_analyzer.py +402 -0
- src/linters/collection_pipeline/linter.py +18 -35
- src/linters/collection_pipeline/suggestion_builder.py +68 -1
- src/linters/dry/base_token_analyzer.py +16 -9
- src/linters/dry/block_filter.py +7 -4
- src/linters/dry/cache.py +7 -2
- src/linters/dry/config.py +7 -1
- src/linters/dry/constant_matcher.py +34 -25
- src/linters/dry/file_analyzer.py +4 -2
- src/linters/dry/inline_ignore.py +7 -16
- src/linters/dry/linter.py +48 -25
- src/linters/dry/python_analyzer.py +18 -10
- src/linters/dry/python_constant_extractor.py +51 -52
- src/linters/dry/single_statement_detector.py +14 -12
- src/linters/dry/token_hasher.py +115 -115
- src/linters/dry/typescript_analyzer.py +11 -6
- src/linters/dry/typescript_constant_extractor.py +4 -0
- src/linters/dry/typescript_statement_detector.py +208 -208
- src/linters/dry/typescript_value_extractor.py +3 -0
- src/linters/dry/violation_filter.py +1 -4
- src/linters/dry/violation_generator.py +1 -4
- src/linters/file_header/atemporal_detector.py +4 -0
- src/linters/file_header/base_parser.py +4 -0
- src/linters/file_header/bash_parser.py +4 -0
- src/linters/file_header/field_validator.py +5 -8
- src/linters/file_header/linter.py +19 -12
- src/linters/file_header/markdown_parser.py +6 -0
- src/linters/file_placement/config_loader.py +3 -1
- src/linters/file_placement/linter.py +22 -8
- src/linters/file_placement/pattern_matcher.py +21 -4
- src/linters/file_placement/pattern_validator.py +21 -7
- src/linters/file_placement/rule_checker.py +2 -2
- src/linters/lazy_ignores/__init__.py +43 -0
- src/linters/lazy_ignores/config.py +66 -0
- src/linters/lazy_ignores/directive_utils.py +121 -0
- src/linters/lazy_ignores/header_parser.py +177 -0
- src/linters/lazy_ignores/linter.py +158 -0
- src/linters/lazy_ignores/matcher.py +135 -0
- src/linters/lazy_ignores/python_analyzer.py +201 -0
- src/linters/lazy_ignores/rule_id_utils.py +180 -0
- src/linters/lazy_ignores/skip_detector.py +298 -0
- src/linters/lazy_ignores/types.py +67 -0
- src/linters/lazy_ignores/typescript_analyzer.py +146 -0
- src/linters/lazy_ignores/violation_builder.py +131 -0
- src/linters/lbyl/__init__.py +29 -0
- src/linters/lbyl/config.py +63 -0
- src/linters/lbyl/pattern_detectors/__init__.py +25 -0
- src/linters/lbyl/pattern_detectors/base.py +46 -0
- src/linters/magic_numbers/context_analyzer.py +227 -229
- src/linters/magic_numbers/linter.py +20 -15
- src/linters/magic_numbers/python_analyzer.py +4 -16
- src/linters/magic_numbers/typescript_analyzer.py +9 -16
- src/linters/method_property/config.py +4 -0
- src/linters/method_property/linter.py +5 -4
- src/linters/method_property/python_analyzer.py +5 -4
- src/linters/method_property/violation_builder.py +3 -0
- src/linters/nesting/typescript_analyzer.py +6 -12
- src/linters/nesting/typescript_function_extractor.py +0 -4
- src/linters/print_statements/linter.py +6 -4
- src/linters/print_statements/python_analyzer.py +85 -81
- src/linters/print_statements/typescript_analyzer.py +6 -15
- src/linters/srp/heuristics.py +4 -4
- src/linters/srp/linter.py +12 -12
- src/linters/srp/violation_builder.py +0 -4
- src/linters/stateless_class/linter.py +30 -36
- src/linters/stateless_class/python_analyzer.py +11 -20
- src/linters/stringly_typed/__init__.py +22 -9
- src/linters/stringly_typed/config.py +32 -8
- src/linters/stringly_typed/context_filter.py +451 -0
- src/linters/stringly_typed/function_call_violation_builder.py +135 -0
- src/linters/stringly_typed/ignore_checker.py +102 -0
- src/linters/stringly_typed/ignore_utils.py +51 -0
- src/linters/stringly_typed/linter.py +376 -0
- src/linters/stringly_typed/python/__init__.py +9 -5
- src/linters/stringly_typed/python/analyzer.py +159 -9
- src/linters/stringly_typed/python/call_tracker.py +175 -0
- src/linters/stringly_typed/python/comparison_tracker.py +257 -0
- src/linters/stringly_typed/python/condition_extractor.py +3 -0
- src/linters/stringly_typed/python/conditional_detector.py +4 -1
- src/linters/stringly_typed/python/match_analyzer.py +8 -2
- src/linters/stringly_typed/python/validation_detector.py +3 -0
- src/linters/stringly_typed/storage.py +630 -0
- src/linters/stringly_typed/storage_initializer.py +45 -0
- src/linters/stringly_typed/typescript/__init__.py +28 -0
- src/linters/stringly_typed/typescript/analyzer.py +157 -0
- src/linters/stringly_typed/typescript/call_tracker.py +335 -0
- src/linters/stringly_typed/typescript/comparison_tracker.py +378 -0
- src/linters/stringly_typed/violation_generator.py +405 -0
- src/orchestrator/core.py +13 -4
- src/templates/thailint_config_template.yaml +166 -0
- src/utils/project_root.py +3 -0
- thailint-0.13.0.dist-info/METADATA +184 -0
- thailint-0.13.0.dist-info/RECORD +189 -0
- thailint-0.11.0.dist-info/METADATA +0 -1661
- thailint-0.11.0.dist-info/RECORD +0 -150
- {thailint-0.11.0.dist-info → thailint-0.13.0.dist-info}/WHEEL +0 -0
- {thailint-0.11.0.dist-info → thailint-0.13.0.dist-info}/entry_points.txt +0 -0
- {thailint-0.11.0.dist-info → thailint-0.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -20,13 +20,20 @@ Interfaces: StatelessClassRule.check(context) -> list[Violation]
|
|
|
20
20
|
|
|
21
21
|
Implementation: Composition pattern delegating analysis to specialized analyzer with
|
|
22
22
|
config loading and comprehensive ignore checking
|
|
23
|
+
|
|
24
|
+
Suppressions:
|
|
25
|
+
- B101: Type narrowing assertion after _should_analyze guard (can't fail)
|
|
26
|
+
- srp,dry: Rule class coordinates analyzer, config, and ignore checking. Method count
|
|
27
|
+
exceeds limit due to comprehensive 5-level ignore system support.
|
|
23
28
|
"""
|
|
24
29
|
|
|
25
30
|
from pathlib import Path
|
|
26
31
|
|
|
27
32
|
from src.core.base import BaseLintContext, BaseLintRule
|
|
33
|
+
from src.core.constants import HEADER_SCAN_LINES, IgnoreDirective, Language
|
|
28
34
|
from src.core.types import Severity, Violation
|
|
29
35
|
from src.linter_config.ignore import get_ignore_parser
|
|
36
|
+
from src.linter_config.rule_matcher import rule_matches
|
|
30
37
|
|
|
31
38
|
from .config import StatelessClassConfig
|
|
32
39
|
from .python_analyzer import ClassInfo, StatelessClassAnalyzer
|
|
@@ -67,20 +74,29 @@ class StatelessClassRule(BaseLintRule): # thailint: ignore[srp,dry]
|
|
|
67
74
|
return []
|
|
68
75
|
|
|
69
76
|
config = self._load_config(context)
|
|
70
|
-
if not config.enabled:
|
|
71
|
-
return []
|
|
72
|
-
|
|
73
|
-
if self._is_file_ignored(context, config):
|
|
77
|
+
if not config.enabled or self._should_skip_file(context, config):
|
|
74
78
|
return []
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
# _should_analyze ensures file_content is set
|
|
81
|
+
assert context.file_content is not None # nosec B101
|
|
78
82
|
|
|
79
83
|
analyzer = StatelessClassAnalyzer(min_methods=config.min_methods)
|
|
80
|
-
stateless_classes = analyzer.analyze(context.file_content)
|
|
84
|
+
stateless_classes = analyzer.analyze(context.file_content)
|
|
81
85
|
|
|
82
86
|
return self._filter_ignored_violations(stateless_classes, context)
|
|
83
87
|
|
|
88
|
+
def _should_skip_file(self, context: BaseLintContext, config: StatelessClassConfig) -> bool:
|
|
89
|
+
"""Check if file should be skipped due to ignore patterns or directives.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
context: Lint context
|
|
93
|
+
config: Configuration
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
True if file should be skipped
|
|
97
|
+
"""
|
|
98
|
+
return self._is_file_ignored(context, config) or self._has_file_level_ignore(context)
|
|
99
|
+
|
|
84
100
|
def _should_analyze(self, context: BaseLintContext) -> bool:
|
|
85
101
|
"""Check if context should be analyzed.
|
|
86
102
|
|
|
@@ -90,7 +106,7 @@ class StatelessClassRule(BaseLintRule): # thailint: ignore[srp,dry]
|
|
|
90
106
|
Returns:
|
|
91
107
|
True if should analyze
|
|
92
108
|
"""
|
|
93
|
-
return context.language ==
|
|
109
|
+
return context.language == Language.PYTHON and context.file_content is not None
|
|
94
110
|
|
|
95
111
|
def _load_config(self, context: BaseLintContext) -> StatelessClassConfig:
|
|
96
112
|
"""Load configuration from context.
|
|
@@ -129,10 +145,7 @@ class StatelessClassRule(BaseLintRule): # thailint: ignore[srp,dry]
|
|
|
129
145
|
return False
|
|
130
146
|
|
|
131
147
|
file_path = Path(context.file_path)
|
|
132
|
-
for pattern in config.ignore
|
|
133
|
-
if self._matches_pattern(file_path, pattern):
|
|
134
|
-
return True
|
|
135
|
-
return False
|
|
148
|
+
return any(self._matches_pattern(file_path, pattern) for pattern in config.ignore)
|
|
136
149
|
|
|
137
150
|
def _matches_pattern(self, file_path: Path, pattern: str) -> bool:
|
|
138
151
|
"""Check if file path matches a glob pattern.
|
|
@@ -162,12 +175,9 @@ class StatelessClassRule(BaseLintRule): # thailint: ignore[srp,dry]
|
|
|
162
175
|
if not context.file_content:
|
|
163
176
|
return False
|
|
164
177
|
|
|
165
|
-
# Check first
|
|
166
|
-
lines = context.file_content.splitlines()[:
|
|
167
|
-
for line in lines
|
|
168
|
-
if self._is_file_ignore_directive(line):
|
|
169
|
-
return True
|
|
170
|
-
return False
|
|
178
|
+
# Check first lines for ignore-file directive
|
|
179
|
+
lines = context.file_content.splitlines()[:HEADER_SCAN_LINES]
|
|
180
|
+
return any(self._is_file_ignore_directive(line) for line in lines)
|
|
171
181
|
|
|
172
182
|
def _is_file_ignore_directive(self, line: str) -> bool:
|
|
173
183
|
"""Check if line is a file-level ignore directive.
|
|
@@ -218,23 +228,7 @@ class StatelessClassRule(BaseLintRule): # thailint: ignore[srp,dry]
|
|
|
218
228
|
Returns:
|
|
219
229
|
True if pattern matches this rule
|
|
220
230
|
"""
|
|
221
|
-
|
|
222
|
-
pattern_lower = rule_pattern.lower()
|
|
223
|
-
|
|
224
|
-
# Exact match
|
|
225
|
-
if rule_id_lower == pattern_lower:
|
|
226
|
-
return True
|
|
227
|
-
|
|
228
|
-
# Prefix match: stateless-class matches stateless-class.violation
|
|
229
|
-
if rule_id_lower.startswith(pattern_lower + "."):
|
|
230
|
-
return True
|
|
231
|
-
|
|
232
|
-
# Wildcard match: stateless-class.* matches stateless-class.violation
|
|
233
|
-
if pattern_lower.endswith("*"):
|
|
234
|
-
prefix = pattern_lower[:-1]
|
|
235
|
-
return rule_id_lower.startswith(prefix)
|
|
236
|
-
|
|
237
|
-
return False
|
|
231
|
+
return rule_matches(self.rule_id, rule_pattern)
|
|
238
232
|
|
|
239
233
|
def _filter_ignored_violations(
|
|
240
234
|
self, classes: list[ClassInfo], context: BaseLintContext
|
|
@@ -330,7 +324,7 @@ class StatelessClassRule(BaseLintRule): # thailint: ignore[srp,dry]
|
|
|
330
324
|
return True
|
|
331
325
|
|
|
332
326
|
# Rule-specific ignore
|
|
333
|
-
return self._matches_rule_ignore(line,
|
|
327
|
+
return self._matches_rule_ignore(line, IgnoreDirective.IGNORE)
|
|
334
328
|
|
|
335
329
|
def _create_violation(self, info: ClassInfo, context: BaseLintContext) -> Violation:
|
|
336
330
|
"""Create violation from class info.
|
|
@@ -145,10 +145,10 @@ def _has_constructor(class_node: ast.ClassDef) -> bool:
|
|
|
145
145
|
True if class has constructor
|
|
146
146
|
"""
|
|
147
147
|
constructor_names = ("__init__", "__new__")
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
return any(
|
|
149
|
+
isinstance(item, ast.FunctionDef) and item.name in constructor_names
|
|
150
|
+
for item in class_node.body
|
|
151
|
+
)
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
def _is_exception_case(class_node: ast.ClassDef) -> bool:
|
|
@@ -174,10 +174,7 @@ def _inherits_from_abc_or_protocol(class_node: ast.ClassDef) -> bool:
|
|
|
174
174
|
Returns:
|
|
175
175
|
True if inherits from ABC or Protocol
|
|
176
176
|
"""
|
|
177
|
-
for base in class_node.bases
|
|
178
|
-
if _get_base_name(base) in ("ABC", "Protocol"):
|
|
179
|
-
return True
|
|
180
|
-
return False
|
|
177
|
+
return any(_get_base_name(base) in ("ABC", "Protocol") for base in class_node.bases)
|
|
181
178
|
|
|
182
179
|
|
|
183
180
|
def _get_base_name(base: ast.expr) -> str:
|
|
@@ -205,10 +202,7 @@ def _has_class_attributes(class_node: ast.ClassDef) -> bool:
|
|
|
205
202
|
Returns:
|
|
206
203
|
True if class has class attributes
|
|
207
204
|
"""
|
|
208
|
-
for item in class_node.body
|
|
209
|
-
if isinstance(item, (ast.Assign, ast.AnnAssign)):
|
|
210
|
-
return True
|
|
211
|
-
return False
|
|
205
|
+
return any(isinstance(item, (ast.Assign, ast.AnnAssign)) for item in class_node.body)
|
|
212
206
|
|
|
213
207
|
|
|
214
208
|
def _has_instance_attributes(class_node: ast.ClassDef) -> bool:
|
|
@@ -220,10 +214,10 @@ def _has_instance_attributes(class_node: ast.ClassDef) -> bool:
|
|
|
220
214
|
Returns:
|
|
221
215
|
True if any method assigns to self
|
|
222
216
|
"""
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
217
|
+
return any(
|
|
218
|
+
isinstance(item, ast.FunctionDef) and _method_has_self_assignment(item)
|
|
219
|
+
for item in class_node.body
|
|
220
|
+
)
|
|
227
221
|
|
|
228
222
|
|
|
229
223
|
def _method_has_self_assignment(method: ast.FunctionDef) -> bool:
|
|
@@ -235,10 +229,7 @@ def _method_has_self_assignment(method: ast.FunctionDef) -> bool:
|
|
|
235
229
|
Returns:
|
|
236
230
|
True if method assigns to self
|
|
237
231
|
"""
|
|
238
|
-
for node in ast.walk(method)
|
|
239
|
-
if _is_self_attribute_assignment(node):
|
|
240
|
-
return True
|
|
241
|
-
return False
|
|
232
|
+
return any(_is_self_attribute_assignment(node) for node in ast.walk(method))
|
|
242
233
|
|
|
243
234
|
|
|
244
235
|
def _is_self_attribute_assignment(node: ast.AST) -> bool:
|
|
@@ -4,20 +4,33 @@ Purpose: Stringly-typed linter package exports
|
|
|
4
4
|
Scope: Public API for stringly-typed linter module
|
|
5
5
|
|
|
6
6
|
Overview: Provides the public interface for the stringly-typed linter package. Exports
|
|
7
|
-
StringlyTypedConfig for configuration
|
|
8
|
-
code patterns where plain strings are used instead of proper enums or typed
|
|
9
|
-
helping identify potential type safety improvements.
|
|
10
|
-
|
|
7
|
+
StringlyTypedConfig for configuration and StringlyTypedRule for linting. The stringly-typed
|
|
8
|
+
linter detects code patterns where plain strings are used instead of proper enums or typed
|
|
9
|
+
alternatives, helping identify potential type safety improvements. Supports cross-file
|
|
10
|
+
detection to find repeated string patterns across the codebase. Includes IgnoreChecker
|
|
11
|
+
for inline ignore directive support.
|
|
11
12
|
|
|
12
|
-
Dependencies: .config for StringlyTypedConfig
|
|
13
|
+
Dependencies: .config for StringlyTypedConfig, .linter for StringlyTypedRule,
|
|
14
|
+
.storage for StringlyTypedStorage, .ignore_checker for IgnoreChecker
|
|
13
15
|
|
|
14
|
-
Exports: StringlyTypedConfig
|
|
16
|
+
Exports: StringlyTypedConfig, StringlyTypedRule, StringlyTypedStorage, StoredPattern,
|
|
17
|
+
IgnoreChecker
|
|
15
18
|
|
|
16
|
-
Interfaces: Configuration loading via StringlyTypedConfig.from_dict()
|
|
19
|
+
Interfaces: Configuration loading via StringlyTypedConfig.from_dict(),
|
|
20
|
+
StringlyTypedRule.check() and finalize() for linting, IgnoreChecker.filter_violations()
|
|
17
21
|
|
|
18
22
|
Implementation: Module-level exports with __all__ definition
|
|
19
23
|
"""
|
|
20
24
|
|
|
21
25
|
from src.linters.stringly_typed.config import StringlyTypedConfig
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
from src.linters.stringly_typed.ignore_checker import IgnoreChecker
|
|
27
|
+
from src.linters.stringly_typed.linter import StringlyTypedRule
|
|
28
|
+
from src.linters.stringly_typed.storage import StoredPattern, StringlyTypedStorage
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"StringlyTypedConfig",
|
|
32
|
+
"IgnoreChecker",
|
|
33
|
+
"StringlyTypedRule",
|
|
34
|
+
"StringlyTypedStorage",
|
|
35
|
+
"StoredPattern",
|
|
36
|
+
]
|
|
@@ -18,11 +18,10 @@ Exports: StringlyTypedConfig dataclass, default constants
|
|
|
18
18
|
Interfaces: StringlyTypedConfig.from_dict() class method for configuration loading
|
|
19
19
|
|
|
20
20
|
Implementation: Dataclass with sensible defaults, validation in __post_init__, and config
|
|
21
|
-
loading from dictionary with language-specific override support
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
the established pattern in DRYConfig which has the same suppression.
|
|
21
|
+
loading from dictionary with language-specific override support
|
|
22
|
+
|
|
23
|
+
Suppressions:
|
|
24
|
+
- too-many-instance-attributes: Configuration dataclass with cohesive detection settings
|
|
26
25
|
"""
|
|
27
26
|
|
|
28
27
|
from dataclasses import dataclass, field
|
|
@@ -33,6 +32,23 @@ DEFAULT_MIN_OCCURRENCES = 2
|
|
|
33
32
|
DEFAULT_MIN_VALUES_FOR_ENUM = 2
|
|
34
33
|
DEFAULT_MAX_VALUES_FOR_ENUM = 6
|
|
35
34
|
|
|
35
|
+
# Default ignore patterns - test directories are excluded by default
|
|
36
|
+
# because test fixtures commonly use string literals for mocking
|
|
37
|
+
DEFAULT_IGNORE_PATTERNS: list[str] = [
|
|
38
|
+
"**/tests/**",
|
|
39
|
+
"**/test/**",
|
|
40
|
+
"**/*_test.py",
|
|
41
|
+
"**/*_test.ts",
|
|
42
|
+
"**/*.test.ts",
|
|
43
|
+
"**/*.test.tsx",
|
|
44
|
+
"**/*.spec.ts",
|
|
45
|
+
"**/*.spec.tsx",
|
|
46
|
+
"**/*.stories.ts",
|
|
47
|
+
"**/*.stories.tsx",
|
|
48
|
+
"**/conftest.py",
|
|
49
|
+
"**/fixtures/**",
|
|
50
|
+
]
|
|
51
|
+
|
|
36
52
|
|
|
37
53
|
@dataclass
|
|
38
54
|
class StringlyTypedConfig: # pylint: disable=too-many-instance-attributes
|
|
@@ -62,7 +78,7 @@ class StringlyTypedConfig: # pylint: disable=too-many-instance-attributes
|
|
|
62
78
|
"""Whether to require cross-file occurrences to flag violations."""
|
|
63
79
|
|
|
64
80
|
ignore: list[str] = field(default_factory=list)
|
|
65
|
-
"""File patterns to ignore."""
|
|
81
|
+
"""File patterns to ignore. Defaults merged with test directories in from_dict."""
|
|
66
82
|
|
|
67
83
|
allowed_string_sets: list[list[str]] = field(default_factory=list)
|
|
68
84
|
"""String sets that are allowed and should not be flagged."""
|
|
@@ -114,13 +130,17 @@ class StringlyTypedConfig: # pylint: disable=too-many-instance-attributes
|
|
|
114
130
|
Returns:
|
|
115
131
|
StringlyTypedConfig instance
|
|
116
132
|
"""
|
|
133
|
+
# Merge user ignore patterns with defaults
|
|
134
|
+
user_ignore = config.get("ignore", [])
|
|
135
|
+
merged_ignore = DEFAULT_IGNORE_PATTERNS.copy() + user_ignore
|
|
136
|
+
|
|
117
137
|
return cls(
|
|
118
138
|
enabled=config.get("enabled", True),
|
|
119
139
|
min_occurrences=config.get("min_occurrences", DEFAULT_MIN_OCCURRENCES),
|
|
120
140
|
min_values_for_enum=config.get("min_values_for_enum", DEFAULT_MIN_VALUES_FOR_ENUM),
|
|
121
141
|
max_values_for_enum=config.get("max_values_for_enum", DEFAULT_MAX_VALUES_FOR_ENUM),
|
|
122
142
|
require_cross_file=config.get("require_cross_file", True),
|
|
123
|
-
ignore=
|
|
143
|
+
ignore=merged_ignore,
|
|
124
144
|
allowed_string_sets=config.get("allowed_string_sets", []),
|
|
125
145
|
exclude_variables=config.get("exclude_variables", []),
|
|
126
146
|
)
|
|
@@ -138,6 +158,10 @@ class StringlyTypedConfig: # pylint: disable=too-many-instance-attributes
|
|
|
138
158
|
Returns:
|
|
139
159
|
StringlyTypedConfig instance with merged values
|
|
140
160
|
"""
|
|
161
|
+
# Merge user ignore patterns with defaults
|
|
162
|
+
user_ignore = lang_config.get("ignore", base_config.get("ignore", []))
|
|
163
|
+
merged_ignore = DEFAULT_IGNORE_PATTERNS.copy() + user_ignore
|
|
164
|
+
|
|
141
165
|
return cls(
|
|
142
166
|
enabled=lang_config.get("enabled", base_config.get("enabled", True)),
|
|
143
167
|
min_occurrences=lang_config.get(
|
|
@@ -155,7 +179,7 @@ class StringlyTypedConfig: # pylint: disable=too-many-instance-attributes
|
|
|
155
179
|
require_cross_file=lang_config.get(
|
|
156
180
|
"require_cross_file", base_config.get("require_cross_file", True)
|
|
157
181
|
),
|
|
158
|
-
ignore=
|
|
182
|
+
ignore=merged_ignore,
|
|
159
183
|
allowed_string_sets=lang_config.get(
|
|
160
184
|
"allowed_string_sets", base_config.get("allowed_string_sets", [])
|
|
161
185
|
),
|