Skip to content

Commit f17383f

Browse files
authored
Merge pull request #86 from Lakitna/__init__.robot-is-wrongly-considered-unused
Init .robot is wrongly considered unused
2 parents 06ff4a3 + 51ebb57 commit f17383f

File tree

18 files changed

+133
-18
lines changed

18 files changed

+133
-18
lines changed

src/robotframework_find_unused/commands/files.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ def cli_files(options: FileOptions):
4646
if len(file_paths) == 0:
4747
return cli_hard_exit(options.verbose)
4848

49-
files = cli_step_parse_file_use(file_paths, verbose=options.verbose)
49+
files = cli_step_parse_file_use(
50+
file_paths,
51+
Path(options.source_path),
52+
verbose=options.verbose,
53+
)
5054

5155
if options.show_tree:
5256
_cli_print_grouped_file_trees(files, options)

src/robotframework_find_unused/commands/step/discover_files.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ def cli_discover_file_paths(input_path: str, *, verbose: int) -> list[Path]:
3131

3232
file_paths = [path[0] for path in robocop_config.paths]
3333
sorted_file_paths = sorted(file_paths, key=lambda f: f)
34+
sorted_file_paths = sorted(
35+
sorted_file_paths,
36+
key=lambda p: len(p.parts)
37+
# __init__ files should always be before the files they apply to
38+
+ (-0.5 if p.stem == "__init__" else 0),
39+
)
3440

3541
_log_file_stats(sorted_file_paths, input_path, verbose)
3642
return sorted_file_paths

src/robotframework_find_unused/commands/step/parse_file_use.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@
1414
from robotframework_find_unused.visitors.robot.file_import import RobotVisitorFileImports
1515

1616

17-
def cli_step_parse_file_use(file_paths: list[Path], *, verbose: int):
17+
def cli_step_parse_file_use(file_paths: list[Path], source_path: Path, *, verbose: int):
1818
"""
1919
Parse files and keep the user up-to-date on progress
2020
"""
2121
click.echo("Parsing file imports...")
2222

23-
files = _count_file_uses(file_paths)
23+
files = _count_file_uses(file_paths, source_path)
2424

2525
_log_file_stats(files, verbose)
2626
return files
2727

2828

29-
def _count_file_uses(file_paths: list[Path]) -> list[FileUseData]:
29+
def _count_file_uses(file_paths: list[Path], source_path: Path) -> list[FileUseData]:
3030
"""
3131
Walk through all robot files to keep track of imports.
3232
"""
33-
visitor = RobotVisitorFileImports()
33+
visitor = RobotVisitorFileImports(source_path)
3434
visit_robot_files(
3535
file_paths,
3636
visitor,

src/robotframework_find_unused/common/cli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def pretty_kw_name(keyword: KeywordData) -> str:
2121
return name
2222

2323

24-
def pretty_file_path(path: str, file_types: set[FileUseType]) -> str:
24+
def pretty_file_path(path: str, file_types: set[FileUseType]) -> str: # noqa: PLR0911
2525
"""
2626
Format file path for output to the user
2727
"""
@@ -36,6 +36,8 @@ def pretty_file_path(path: str, file_types: set[FileUseType]) -> str:
3636
return click.style(path, fg="bright_cyan")
3737
if file_type == "SUITE":
3838
return path
39+
if file_type == "SUITE_INIT":
40+
return path
3941
if file_type == "LIBRARY":
4042
return click.style(path, fg="bright_magenta")
4143
if file_type == "VARIABLE":

src/robotframework_find_unused/common/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class LibraryData:
8383

8484
FileUseType: TypeAlias = Literal[
8585
"SUITE",
86+
"SUITE_INIT",
8687
"RESOURCE",
8788
"LIBRARY",
8889
"VARIABLE",

src/robotframework_find_unused/visitors/robot/file_import.py

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@ class RobotVisitorFileImports(ModelVisitor):
2323
Gather file imports
2424
"""
2525

26+
root_directory: Path
2627
files: dict[str, FileUseData]
28+
init_files: dict[Path, FileUseData]
2729
current_working_file: FileUseData | None = None
2830
current_working_directory: Path | None = None
2931

30-
def __init__(self) -> None:
32+
def __init__(self, root_directory: Path) -> None:
33+
self.root_directory = root_directory.absolute()
3134
self.files = {}
35+
self.init_files = {}
3236
super().__init__()
3337

3438
def visit_File(self, node: File): # noqa: N802
@@ -48,21 +52,63 @@ def visit_File(self, node: File): # noqa: N802
4852
# Already found as import
4953
self.current_working_file = self.files[current_file_path_normalized]
5054
else:
51-
self.current_working_file = FileUseData(
52-
normalize_file_path(current_working_file),
53-
path_absolute=current_working_file,
54-
type={file_type},
55-
used_by=[],
55+
self.current_working_file = self._register_file(
56+
current_file_path_normalized,
57+
file_type,
58+
current_working_file,
5659
)
57-
self.files[current_file_path_normalized] = self.current_working_file
5860

5961
return self.generic_visit(node)
6062

63+
def _register_file(
64+
self,
65+
current_file_path_normalized: str,
66+
file_type: Literal["SUITE", "SUITE_INIT", "RESOURCE"],
67+
current_working_file: Path,
68+
) -> FileUseData:
69+
"""Register a file"""
70+
file = FileUseData(
71+
id=current_file_path_normalized,
72+
path_absolute=current_working_file,
73+
type={file_type},
74+
used_by=[],
75+
)
76+
77+
if file_type == "SUITE_INIT":
78+
self.init_files[current_working_file.parent] = file
79+
80+
# Assumption: Due to file path sorting, `__init__` is always processed before any suite
81+
# file it applies to.
82+
83+
if file_type == "SUITE":
84+
self._register_use_of_suite_init(file)
85+
86+
self.files[current_file_path_normalized] = file
87+
return file
88+
89+
def _register_use_of_suite_init(self, file: FileUseData) -> None:
90+
"""Register use of suite __init__ files"""
91+
if len(self.init_files) == 0:
92+
return
93+
94+
root_dir_parts_len = len(self.root_directory.parts)
95+
96+
path = file.path_absolute
97+
while len(path.parts) > root_dir_parts_len:
98+
path = path.parent
99+
init_file = self.init_files.get(path, None)
100+
101+
if init_file:
102+
init_file.used_by.append(file)
103+
61104
def _get_file_type(
62105
self,
63106
file_node: File,
64107
file_path: Path,
65-
) -> Literal["SUITE", "RESOURCE"] | None:
108+
) -> Literal["SUITE", "SUITE_INIT", "RESOURCE"] | None:
109+
if file_path.stem == "__init__":
110+
return "SUITE_INIT"
111+
66112
file_extension = file_path.suffix.lstrip(".").lower()
67113

68114
if file_extension == "robot":
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Discovering files in `./robot` using Robocop config...
22
Parsing file imports...
3-
[ DONE ] Parsed 4 files
3+
[ DONE ] Parsed 5 files
44

55
Found 1 unused files:
66
./gamma.resource
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
Discovering files in `./robot` using Robocop config...
22
Parsing file imports...
3-
[ DONE ] Parsed 4 files
3+
[ DONE ] Parsed 5 files
44

55
import_count file
66
0 ./gamma.resource
7+
1 ./__init__.robot
78
1 ./alpha.resource
89
2 ./beta.resource
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
Discovering files in `./robot` using Robocop config...
22
Parsing file imports...
3-
[ DONE ] Parsed 4 files
3+
[ DONE ] Parsed 5 files
44
Building 1 file import trees...
55
Printing 1 tree groups...
66

77
[[REPOSITORY_ROOT]]/test/atest/files/basic/robot/test.robot
8+
│ ./__init__.robot
89
│ ./alpha.resource
910
│ │ ./beta.resource
1011
│ ./beta.resource [Already imported]
11-
Tree height: 4 | Tree depth: 2 | Unique files: 3 | Circular imports: 0 | Already imported: 1
12+
Tree height: 5 | Tree depth: 2 | Unique files: 4 | Circular imports: 0 | Already imported: 1
1213

1314
Found 1 unused files:
1415
./gamma.resource

test/atest/files/basic/robot/__init__.robot

Whitespace-only changes.

0 commit comments

Comments
 (0)