Skip to content

Commit 4d9b4fd

Browse files
committed
chore(lint): lint/formatted codebase
1 parent c83107c commit 4d9b4fd

9 files changed

Lines changed: 86 additions & 26 deletions

File tree

.serena/project.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,8 @@ language_backend:
130130
# list of regex patterns which, when matched, mark a memory entry as read‑only.
131131
# Extends the list from the global configuration, merging the two lists.
132132
read_only_memory_patterns: []
133+
134+
# line ending convention to use when writing source files.
135+
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
136+
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
137+
line_ending:

src/exportify/commands/sync.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from exportify.commands.utils import (
2323
CONSOLE,
2424
collect_py_files,
25+
display_path,
2526
get_all_source_roots,
2627
load_config_and_rules,
2728
path_to_module,
@@ -76,7 +77,7 @@ def _print_sync_results(result: ExportGenerationResult) -> None:
7677

7778
def _report_module_all_dry_run(py_file: Path, result: ModuleAllFixResult) -> None:
7879
"""Print dry-run diff for a single module __all__ fix."""
79-
print_info(f"Would update {py_file}")
80+
print_info(f"Would update {display_path(py_file)}")
8081
if result.added:
8182
CONSOLE.print(f" [green]+[/green] Add to __all__: {result.added}")
8283
if result.removed:
@@ -87,7 +88,7 @@ def _report_module_all_dry_run(py_file: Path, result: ModuleAllFixResult) -> Non
8788

8889
def _report_module_all_applied(py_file: Path, result: ModuleAllFixResult, *, verbose: bool) -> None:
8990
"""Print applied-fix info for a single module __all__ fix."""
90-
print_success(f"Updated {py_file}")
91+
print_success(f"Updated {display_path(py_file)}")
9192
if not verbose:
9293
return
9394
if result.added:

src/exportify/commands/utils.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from exportify.common.config import CONFIG_ENV_VAR, ExportifyConfig, find_config_file, load_config
1616
from exportify.export_manager import RuleEngine
1717
from exportify.types import ValidationReport
18-
from exportify.utils import detect_source_root, locate_project_root
18+
from exportify.utils import detect_source_root, display_path, locate_project_root
1919

2020

2121
logger = logging.getLogger(__name__)
@@ -46,12 +46,14 @@ def resolve_checks(all_checks: set[str], **flags: bool | None) -> set[str]:
4646

4747
def get_all_source_roots(source_override: Path | None = None) -> list[Path]:
4848
"""Get all source roots: primary (detected or overridden) + additional from config."""
49-
source_root = source_override or detect_source_root()
49+
source_root = (source_override or detect_source_root()).resolve()
5050
additional_source_roots: list[Path] = []
5151

5252
if config_path := find_config_file():
5353
config = load_config(config_path)
54-
additional_source_roots = config.project.additional_source_paths
54+
additional_source_roots = [
55+
Path(p).resolve() for p in config.project.additional_source_paths
56+
]
5557

5658
return [source_root, *additional_source_roots]
5759

@@ -206,15 +208,23 @@ def print_output_validation_verbose(results: ValidationReport) -> None:
206208
CONSOLE.print(f"[red]Errors found: {len(results.errors)}[/red]")
207209
CONSOLE.print()
208210
for error in results.errors:
209-
location = f"{error.file}:{error.line}" if error.line else str(error.file)
211+
location = (
212+
f"{display_path(error.file)}:{error.line}"
213+
if error.line
214+
else display_path(error.file)
215+
)
210216
CONSOLE.print(f"[red]ERROR[/red] {location}: [bold]{error.code}[/bold]")
211217
_print_error_in_validation(error)
212218
# Show warnings with full context
213219
if results.warnings:
214220
CONSOLE.print(f"[yellow]Warnings found: {len(results.warnings)}[/yellow]")
215221
CONSOLE.print()
216222
for warning in results.warnings:
217-
location = f"{warning.file}:{warning.line}" if warning.line else str(warning.file)
223+
location = (
224+
f"{display_path(warning.file)}:{warning.line}"
225+
if warning.line
226+
else display_path(warning.file)
227+
)
218228
CONSOLE.print(f"[yellow]WARNING[/yellow] {location}")
219229
_print_error_in_validation(warning)
220230
# Show metrics
@@ -231,12 +241,20 @@ def print_output_validation_concise(results: ValidationReport) -> None:
231241
"""Output validation results in concise human-readable format."""
232242
if results.errors:
233243
for error in results.errors:
234-
location = f"{error.file}:{error.line}" if error.line else str(error.file)
244+
location = (
245+
f"{display_path(error.file)}:{error.line}"
246+
if error.line
247+
else display_path(error.file)
248+
)
235249
CONSOLE.print(f"[red][ERROR][/red] {location}: {error.code} ({error.message})")
236250

237251
if results.warnings:
238252
for warning in results.warnings:
239-
location = f"{warning.file}:{warning.line}" if warning.line else str(warning.file)
253+
location = (
254+
f"{display_path(warning.file)}:{warning.line}"
255+
if warning.line
256+
else display_path(warning.file)
257+
)
240258
CONSOLE.print(f"[yellow][WARNING][/yellow] {location}: {warning.message}")
241259

242260
# Show summary
@@ -261,19 +279,23 @@ def collect_py_files(paths: tuple[Path, ...], source: Path | None) -> list[Path]
261279
Returns:
262280
List of Python file paths to process.
263281
"""
282+
from exportify.discovery.file_discovery import FileDiscovery
283+
284+
discovery = FileDiscovery()
285+
264286
if not paths:
265287
source_root = source or detect_source_root()
266-
return list(source_root.rglob("*.py"))
288+
return discovery.discover_python_files(source_root)
267289

268290
all_files: list[Path] = []
269291
for p in paths:
270292
if not p.exists():
271293
print_error(f"Path does not exist: {p}")
272294
raise SystemExit(1)
273295
if p.is_file():
274-
all_files.append(p)
296+
all_files.append(p.resolve())
275297
else:
276-
all_files.extend(p.rglob("*.py"))
298+
all_files.extend(discovery.discover_python_files(p.resolve()))
277299
return all_files
278300

279301

src/exportify/discovery/file_discovery.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,25 @@ def discover_python_files(
6262

6363
python_files = []
6464

65+
# Common directories to always skip
66+
skip_dirs = {
67+
"__pycache__",
68+
".venv",
69+
"venv",
70+
".git",
71+
".hg",
72+
".mypy_cache",
73+
".pytest_cache",
74+
".ruff_cache",
75+
"build",
76+
"dist",
77+
"node_modules",
78+
}
79+
6580
# Use rglob to recursively find all .py files
6681
for py_file in root.rglob("*.py"):
67-
# Skip __pycache__ directories
68-
if "__pycache__" in py_file.parts:
82+
# Skip common directories
83+
if any(d in py_file.parts for d in skip_dirs):
6984
continue
7085

7186
# Skip if gitignored

src/exportify/export_manager/module_all.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from exportify.analysis.ast_parser import ASTParser
2929
from exportify.common.types import RuleAction, SymbolProvenance
3030
from exportify.export_manager.rules import RuleEngine
31+
from exportify.utils import display_path
3132

3233

3334
# ---------------------------------------------------------------------------
@@ -331,7 +332,7 @@ def check_module_all(file: Path, module_path: str, rules: RuleEngine) -> list[Mo
331332
issue_type="no_all",
332333
symbol_name="",
333334
message=(
334-
f"{file}: __all__ is absent but {len(should_export)} export(s) "
335+
f"{display_path(file)}: __all__ is absent but {len(should_export)} export(s) "
335336
f"are prescribed by rules: {sorted(should_export)}"
336337
),
337338
)
@@ -344,7 +345,7 @@ def check_module_all(file: Path, module_path: str, rules: RuleEngine) -> list[Mo
344345
issue_type="missing",
345346
symbol_name=name,
346347
message=(
347-
f"{file}: '{name}' should be in __all__ (rules prescribe INCLUDE) but is absent"
348+
f"{display_path(file)}: '{name}' should be in __all__ (rules prescribe INCLUDE) but is absent"
348349
),
349350
)
350351
for name in sorted(should_export - actual)
@@ -355,7 +356,7 @@ def check_module_all(file: Path, module_path: str, rules: RuleEngine) -> list[Mo
355356
file=file,
356357
issue_type="extra",
357358
symbol_name=name,
358-
message=(f"{file}: '{name}' is in __all__ but rules say EXCLUDE"),
359+
message=(f"{display_path(file)}: '{name}' is in __all__ but rules say EXCLUDE"),
359360
)
360361
for name in sorted(actual & should_exclude)
361362
)

src/exportify/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,16 @@ def write_gitignore_patterns(exportify_dir: Path | None = None) -> None:
316316
gitignore_path.write_text("\n".join(gitignore_patterns) + "\n")
317317

318318

319+
def display_path(path: Path) -> str:
320+
"""Format a path for display, relative to CWD if possible."""
321+
try:
322+
# We use resolve() on CWD to ensure we're comparing absolute paths
323+
# since 'path' is usually resolved.
324+
return str(path.relative_to(Path.cwd().resolve()))
325+
except ValueError:
326+
return str(path)
327+
328+
319329
def find_project_name() -> str:
320330
"""Find the project name from pyproject.toml or fallback to directory name."""
321331
if (data := _read_pyproject()) and (name := data.get("project", {}).get("name")):

src/exportify/validator/validator.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,9 @@ def validate(self, file_paths: list[Path] | None = None) -> ValidationReport:
308308

309309
for init_file in init_files:
310310
tree = parsed_trees.get(init_file)
311-
consistency_issues = self.consistency_checker.check_file_consistency(init_file, tree=tree)
311+
consistency_issues = self.consistency_checker.check_file_consistency(
312+
init_file, tree=tree
313+
)
312314
consistency_checks += len(consistency_issues)
313315

314316
# Convert ConsistencyIssue to ValidationError/Warning

tests/fixtures/sample_type_aliases.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@
1212
from __future__ import annotations
1313

1414
from pathlib import Path
15-
from typing import TYPE_CHECKING, TypeAlias
15+
from typing import TYPE_CHECKING
1616

1717

1818
if TYPE_CHECKING:
1919
# Dummy usage of type aliases to keep static analyzers happy.
2020
test_file_path: FilePath | None = None
2121

2222
# Pre-3.12 style type aliases (X: TypeAlias = Y)
23-
FilePath: TypeAlias = str | Path
24-
ModuleName: TypeAlias = str
25-
RulePattern: TypeAlias = str
26-
ExportName: TypeAlias = str
27-
ErrorMessage: TypeAlias = str
28-
ConfigDict: TypeAlias = dict[str, str | int | bool | list[str]]
29-
NamePair: TypeAlias = tuple[str, str]
23+
type FilePath = str | Path
24+
type ModuleName = str
25+
type RulePattern = str
26+
type ExportName = str
27+
type ErrorMessage = str
28+
type ConfigDict = dict[str, str | int | bool | list[str]]
29+
type NamePair = tuple[str, str]
3030

3131
# Python 3.12+ style type aliases (type X = Y)
3232
type FileContent = str

tests/test_userspace.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# SPDX-FileCopyrightText: 2026 Knitli Inc.
2+
#
3+
# SPDX-License-Identifier: MIT OR Apache-2.0
4+
15
import ast
26
import contextlib
37

0 commit comments

Comments
 (0)