|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | | -import hashlib |
4 | 3 | from typing import TYPE_CHECKING, NoReturn |
5 | 4 |
|
6 | 5 | import typer |
@@ -42,25 +41,39 @@ def get_model_for_file_type(self, source: Path, language: list[str] | None) -> F |
42 | 41 | return get_resource_with_lang(get_resource_model, source, language) |
43 | 42 | return get_resource_with_lang(get_model, source, language) |
44 | 43 |
|
45 | | - @staticmethod |
46 | | - def _compute_cache_key(config: Config) -> str: |
| 44 | + def get_cached_diagnostics(self, config: Config, source: Path) -> list[Diagnostic] | None: |
47 | 45 | """ |
48 | | - Compute cache key combining linter config hash with language. |
| 46 | + Return cached diagnostics if available. |
49 | 47 |
|
50 | | - Uses SHA256 for stable hashing across Python processes, unlike the built-in |
51 | | - hash() which can vary due to hash randomization (PEP 456). |
| 48 | + Returns: |
| 49 | + List of cached diagnostics or None if no cache is available. |
| 50 | +
|
| 51 | + """ |
| 52 | + if not config.cache.enabled: |
| 53 | + return None |
| 54 | + cached_entry = self.config_manager.cache.get_linter_entry(source, config.hash()) |
| 55 | + |
| 56 | + if cached_entry is not None: |
| 57 | + restored = restore_diagnostics(cached_entry, source, config.linter.rules) |
| 58 | + if restored is not None: |
| 59 | + return restored |
| 60 | + return None |
| 61 | + |
| 62 | + def get_model_diagnostics(self, config: Config, source: Path) -> list[Diagnostic] | None: |
| 63 | + """ |
| 64 | + Run all selected rules on the model and return list of diagnostics. |
52 | 65 |
|
53 | 66 | Returns: |
54 | | - str: The computed cache key as a hexadecimal digest. |
| 67 | + List of diagnostics or None if file cannot be decoded. |
55 | 68 |
|
56 | 69 | """ |
57 | | - hasher = hashlib.sha256() |
58 | | - # Hash the linter config |
59 | | - hasher.update(str(hash(config.linter)).encode("utf-8")) |
60 | | - # Hash the language configuration (affects parsing) |
61 | | - language_str = ":".join(sorted(config.language or [])) |
62 | | - hasher.update(language_str.encode("utf-8")) |
63 | | - return hasher.hexdigest() |
| 70 | + try: |
| 71 | + model = self.get_model_for_file_type(source, config.language) |
| 72 | + return self.run_check(model, source, config) |
| 73 | + except DataError as error: |
| 74 | + if not config.silent: |
| 75 | + print(f"Failed to decode {source} with an error: {error}. Skipping file") |
| 76 | + return None |
64 | 77 |
|
65 | 78 | def run(self) -> list[Diagnostic]: |
66 | 79 | """ |
@@ -89,36 +102,18 @@ def run(self) -> list[Diagnostic]: |
89 | 102 | for source, config in self.config_manager.paths: |
90 | 103 | if config.verbose: |
91 | 104 | print(f"Scanning file: {source}") |
92 | | - |
93 | | - # Try to get cached diagnostics |
94 | | - config_hash = self._compute_cache_key(config) |
95 | | - cached_entry = self.config_manager.cache.get_linter_entry(source, config_hash) |
96 | | - |
97 | | - if cached_entry is not None: |
98 | | - # Restore diagnostics from cache |
99 | | - restored = restore_diagnostics(cached_entry, source, config.linter.rules) |
100 | | - if restored is not None: |
101 | | - self.diagnostics.extend(restored) |
102 | | - files += 1 |
103 | | - cached_files += 1 |
104 | | - continue |
105 | | - # If restoration failed (e.g., rule removed), fall through to reprocess |
106 | | - |
107 | | - try: |
108 | | - model = self.get_model_for_file_type(source, config.language) |
109 | | - except DataError as error: |
110 | | - if not config.silent: |
111 | | - print(f"Failed to decode {source} with an error: {error}. Skipping file") |
| 105 | + diagnostics = self.get_cached_diagnostics(config, source) |
| 106 | + if diagnostics is not None: |
| 107 | + self.diagnostics.extend(diagnostics) |
| 108 | + files += 1 |
| 109 | + cached_files += 1 |
| 110 | + continue |
| 111 | + diagnostics = self.get_model_diagnostics(config, source) |
| 112 | + if diagnostics is None: |
112 | 113 | continue |
113 | | - |
114 | | - files += 1 |
115 | | - diagnostics = self.run_check(model, source, config) |
116 | 114 | self.diagnostics.extend(diagnostics) |
117 | | - |
118 | | - # Cache the results (config_hash already includes language) |
119 | | - self.config_manager.cache.set_linter_entry(source, config_hash, diagnostics) |
120 | | - |
121 | | - # Save cache at the end |
| 115 | + files += 1 |
| 116 | + self.config_manager.cache.set_linter_entry(source, config.hash(), diagnostics) |
122 | 117 | self.config_manager.cache.save() |
123 | 118 |
|
124 | 119 | if not files and not self.config_manager.default_config.silent: |
|
0 commit comments