lintro 0.3.2__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.

Potentially problematic release.


This version of lintro might be problematic. Click here for more details.

Files changed (85) hide show
  1. lintro/__init__.py +3 -0
  2. lintro/__main__.py +6 -0
  3. lintro/ascii-art/fail.txt +404 -0
  4. lintro/ascii-art/success.txt +484 -0
  5. lintro/cli.py +70 -0
  6. lintro/cli_utils/__init__.py +7 -0
  7. lintro/cli_utils/commands/__init__.py +7 -0
  8. lintro/cli_utils/commands/check.py +210 -0
  9. lintro/cli_utils/commands/format.py +167 -0
  10. lintro/cli_utils/commands/list_tools.py +114 -0
  11. lintro/enums/__init__.py +0 -0
  12. lintro/enums/action.py +29 -0
  13. lintro/enums/darglint_strictness.py +22 -0
  14. lintro/enums/group_by.py +31 -0
  15. lintro/enums/hadolint_enums.py +46 -0
  16. lintro/enums/output_format.py +40 -0
  17. lintro/enums/tool_name.py +36 -0
  18. lintro/enums/tool_type.py +27 -0
  19. lintro/enums/yamllint_format.py +22 -0
  20. lintro/exceptions/__init__.py +0 -0
  21. lintro/exceptions/errors.py +15 -0
  22. lintro/formatters/__init__.py +0 -0
  23. lintro/formatters/core/__init__.py +0 -0
  24. lintro/formatters/core/output_style.py +21 -0
  25. lintro/formatters/core/table_descriptor.py +24 -0
  26. lintro/formatters/styles/__init__.py +17 -0
  27. lintro/formatters/styles/csv.py +41 -0
  28. lintro/formatters/styles/grid.py +91 -0
  29. lintro/formatters/styles/html.py +48 -0
  30. lintro/formatters/styles/json.py +61 -0
  31. lintro/formatters/styles/markdown.py +41 -0
  32. lintro/formatters/styles/plain.py +39 -0
  33. lintro/formatters/tools/__init__.py +35 -0
  34. lintro/formatters/tools/darglint_formatter.py +72 -0
  35. lintro/formatters/tools/hadolint_formatter.py +84 -0
  36. lintro/formatters/tools/prettier_formatter.py +76 -0
  37. lintro/formatters/tools/ruff_formatter.py +116 -0
  38. lintro/formatters/tools/yamllint_formatter.py +87 -0
  39. lintro/models/__init__.py +0 -0
  40. lintro/models/core/__init__.py +0 -0
  41. lintro/models/core/tool.py +104 -0
  42. lintro/models/core/tool_config.py +23 -0
  43. lintro/models/core/tool_result.py +39 -0
  44. lintro/parsers/__init__.py +0 -0
  45. lintro/parsers/darglint/__init__.py +0 -0
  46. lintro/parsers/darglint/darglint_issue.py +9 -0
  47. lintro/parsers/darglint/darglint_parser.py +62 -0
  48. lintro/parsers/hadolint/__init__.py +1 -0
  49. lintro/parsers/hadolint/hadolint_issue.py +24 -0
  50. lintro/parsers/hadolint/hadolint_parser.py +65 -0
  51. lintro/parsers/prettier/__init__.py +0 -0
  52. lintro/parsers/prettier/prettier_issue.py +10 -0
  53. lintro/parsers/prettier/prettier_parser.py +60 -0
  54. lintro/parsers/ruff/__init__.py +1 -0
  55. lintro/parsers/ruff/ruff_issue.py +43 -0
  56. lintro/parsers/ruff/ruff_parser.py +89 -0
  57. lintro/parsers/yamllint/__init__.py +0 -0
  58. lintro/parsers/yamllint/yamllint_issue.py +24 -0
  59. lintro/parsers/yamllint/yamllint_parser.py +68 -0
  60. lintro/tools/__init__.py +40 -0
  61. lintro/tools/core/__init__.py +0 -0
  62. lintro/tools/core/tool_base.py +320 -0
  63. lintro/tools/core/tool_manager.py +167 -0
  64. lintro/tools/implementations/__init__.py +0 -0
  65. lintro/tools/implementations/tool_darglint.py +245 -0
  66. lintro/tools/implementations/tool_hadolint.py +302 -0
  67. lintro/tools/implementations/tool_prettier.py +270 -0
  68. lintro/tools/implementations/tool_ruff.py +618 -0
  69. lintro/tools/implementations/tool_yamllint.py +240 -0
  70. lintro/tools/tool_enum.py +17 -0
  71. lintro/utils/__init__.py +0 -0
  72. lintro/utils/ascii_normalize_cli.py +84 -0
  73. lintro/utils/config.py +39 -0
  74. lintro/utils/console_logger.py +783 -0
  75. lintro/utils/formatting.py +173 -0
  76. lintro/utils/output_manager.py +301 -0
  77. lintro/utils/path_utils.py +41 -0
  78. lintro/utils/tool_executor.py +443 -0
  79. lintro/utils/tool_utils.py +431 -0
  80. lintro-0.3.2.dist-info/METADATA +338 -0
  81. lintro-0.3.2.dist-info/RECORD +85 -0
  82. lintro-0.3.2.dist-info/WHEEL +5 -0
  83. lintro-0.3.2.dist-info/entry_points.txt +2 -0
  84. lintro-0.3.2.dist-info/licenses/LICENSE +21 -0
  85. lintro-0.3.2.dist-info/top_level.txt +1 -0
lintro/cli.py ADDED
@@ -0,0 +1,70 @@
1
+ """Command-line interface for Lintro."""
2
+
3
+ import click
4
+
5
+ from lintro import __version__
6
+ from lintro.cli_utils.commands.check import check_command
7
+ from lintro.cli_utils.commands.format import format_code
8
+ from lintro.cli_utils.commands.list_tools import list_tools_command
9
+
10
+
11
+ class LintroGroup(click.Group):
12
+ def format_commands(
13
+ self,
14
+ ctx: click.Context,
15
+ formatter: click.HelpFormatter,
16
+ ) -> None:
17
+ """Render command list with aliases in the help output.
18
+
19
+ Args:
20
+ ctx: click.Context: The Click context.
21
+ formatter: click.HelpFormatter: The help formatter to write to.
22
+ """
23
+ # Group commands by canonical name and aliases
24
+ commands = self.list_commands(ctx)
25
+ # Map canonical name to (command, [aliases])
26
+ canonical_map = {}
27
+ for name in commands:
28
+ cmd = self.get_command(ctx, name)
29
+ if not hasattr(cmd, "_canonical_name"):
30
+ cmd._canonical_name = name
31
+ canonical = cmd._canonical_name
32
+ if canonical not in canonical_map:
33
+ canonical_map[canonical] = (cmd, [])
34
+ if name != canonical:
35
+ canonical_map[canonical][1].append(name)
36
+ rows = []
37
+ for canonical, (cmd, aliases) in canonical_map.items():
38
+ names = [canonical] + aliases
39
+ name_str = " / ".join(names)
40
+ rows.append((name_str, cmd.get_short_help_str()))
41
+ if rows:
42
+ with formatter.section("Commands"):
43
+ formatter.write_dl(rows)
44
+
45
+
46
+ @click.group(cls=LintroGroup, invoke_without_command=True)
47
+ @click.version_option(version=__version__)
48
+ def cli() -> None:
49
+ """Lintro: Unified CLI for code formatting, linting, and quality assurance."""
50
+ pass
51
+
52
+
53
+ # Register canonical commands and set _canonical_name for help
54
+ check_command._canonical_name = "check"
55
+ format_code._canonical_name = "format"
56
+ list_tools_command._canonical_name = "list-tools"
57
+
58
+ cli.add_command(check_command, name="check")
59
+ cli.add_command(format_code, name="format")
60
+ cli.add_command(list_tools_command, name="list-tools")
61
+
62
+ # Register aliases
63
+ cli.add_command(check_command, name="chk")
64
+ cli.add_command(format_code, name="fmt")
65
+ cli.add_command(list_tools_command, name="ls")
66
+
67
+
68
+ def main() -> None:
69
+ """Entry point for the CLI."""
70
+ cli()
@@ -0,0 +1,7 @@
1
+ """CLI utilities package for lintro.
2
+
3
+ This package contains command implementations and utilities for the lintro CLI.
4
+ """
5
+
6
+ # Note: Not importing cli and main here to avoid circular imports
7
+ # They can be imported directly from lintro.cli where needed
@@ -0,0 +1,7 @@
1
+ """CLI command modules for lintro."""
2
+
3
+ from .check import check_command
4
+ from .format import format_code, format_code_legacy
5
+ from .list_tools import list_tools
6
+
7
+ __all__ = ["check_command", "format_code", "format_code_legacy", "list_tools"]
@@ -0,0 +1,210 @@
1
+ """Check command implementation for lintro CLI.
2
+
3
+ This module provides the core logic for the 'check' command.
4
+
5
+ Functions:
6
+ check_command: CLI command for checking files with various tools.
7
+ check: Programmatic function for backward compatibility.
8
+ """
9
+
10
+ import sys
11
+
12
+ import click
13
+ from click.testing import CliRunner
14
+
15
+ from lintro.utils.tool_executor import run_lint_tools_simple
16
+
17
+ # Constants
18
+ DEFAULT_PATHS: list[str] = ["."]
19
+ DEFAULT_EXIT_CODE: int = 0
20
+ DEFAULT_ACTION: str = "check"
21
+
22
+
23
+ @click.command("check")
24
+ @click.argument("paths", nargs=-1, type=click.Path(exists=True))
25
+ @click.option(
26
+ "--tools",
27
+ type=str,
28
+ help='Comma-separated list of tools to run. Use "all" to run all available tools.',
29
+ )
30
+ @click.option(
31
+ "--tool-options",
32
+ type=str,
33
+ help="Tool-specific options in the format tool:option=value,tool:option=value",
34
+ )
35
+ @click.option(
36
+ "--exclude",
37
+ type=str,
38
+ help="Comma-separated list of patterns to exclude from processing",
39
+ )
40
+ @click.option(
41
+ "--include-venv",
42
+ is_flag=True,
43
+ help="Include virtual environment directories in processing",
44
+ )
45
+ @click.option(
46
+ "--output",
47
+ type=click.Path(),
48
+ help="Output file path for writing results",
49
+ )
50
+ @click.option(
51
+ "--output-format",
52
+ type=click.Choice(["plain", "grid", "markdown", "html", "json", "csv"]),
53
+ default="grid",
54
+ help="Output format for displaying results",
55
+ )
56
+ @click.option(
57
+ "--group-by",
58
+ type=click.Choice(["file", "code", "none", "auto"]),
59
+ default="file",
60
+ help="How to group issues in the output",
61
+ )
62
+ @click.option(
63
+ "--ignore-conflicts",
64
+ is_flag=True,
65
+ help="Ignore potential conflicts between tools",
66
+ )
67
+ @click.option(
68
+ "--verbose",
69
+ is_flag=True,
70
+ help="Show verbose output",
71
+ )
72
+ @click.option(
73
+ "--no-log",
74
+ is_flag=True,
75
+ help="Disable logging to file",
76
+ )
77
+ @click.option(
78
+ "--raw-output",
79
+ is_flag=True,
80
+ help="Show raw tool output instead of formatted output",
81
+ )
82
+ def check_command(
83
+ paths,
84
+ tools,
85
+ tool_options,
86
+ exclude,
87
+ include_venv,
88
+ output,
89
+ output_format,
90
+ group_by,
91
+ ignore_conflicts,
92
+ verbose,
93
+ no_log,
94
+ raw_output,
95
+ ) -> None:
96
+ """Check files for issues using the specified tools.
97
+
98
+ Args:
99
+ paths: tuple: List of file/directory paths to check.
100
+ tools: str | None: Comma-separated list of tool names to run.
101
+ tool_options: str | None: Tool-specific configuration options.
102
+ exclude: str | None: Comma-separated patterns of files/dirs to exclude.
103
+ include_venv: bool: Whether to include virtual environment directories.
104
+ output: str | None: Path to output file for results.
105
+ output_format: str: Format for displaying results (table, json, etc).
106
+ group_by: str: How to group issues in output (tool, file, etc).
107
+ ignore_conflicts: bool: Whether to ignore tool configuration conflicts.
108
+ verbose: bool: Whether to show verbose output during execution.
109
+ no_log: bool: Whether to disable logging to file.
110
+ raw_output: bool: Whether to show raw tool output instead of formatted output.
111
+
112
+ Raises:
113
+ SystemExit: Process exit with the aggregated exit code from tools.
114
+ """
115
+ # Add default paths if none provided
116
+ if not paths:
117
+ paths = DEFAULT_PATHS
118
+
119
+ # Build tool-specific options string
120
+ tool_option_parts: list[str] = []
121
+ if tool_options:
122
+ tool_option_parts.append(tool_options)
123
+
124
+ # Removed darglint_timeout and prettier_timeout handling
125
+ combined_tool_options: str | None = (
126
+ ",".join(tool_option_parts) if tool_option_parts else None
127
+ )
128
+
129
+ # Run with simplified approach
130
+ exit_code: int = run_lint_tools_simple(
131
+ action=DEFAULT_ACTION,
132
+ paths=list(paths),
133
+ tools=tools,
134
+ tool_options=combined_tool_options,
135
+ exclude=exclude,
136
+ include_venv=include_venv,
137
+ group_by=group_by,
138
+ output_format=output_format,
139
+ verbose=verbose,
140
+ raw_output=raw_output,
141
+ )
142
+
143
+ # Exit with code only; CLI uses this as process exit code and avoids any
144
+ # additional trailing output after the logger's ASCII art.
145
+ raise SystemExit(exit_code)
146
+
147
+
148
+ def check(
149
+ paths,
150
+ tools,
151
+ tool_options,
152
+ exclude,
153
+ include_venv,
154
+ output,
155
+ output_format,
156
+ group_by,
157
+ ignore_conflicts,
158
+ verbose,
159
+ no_log,
160
+ ) -> None:
161
+ """Programmatic check function for backward compatibility.
162
+
163
+ Args:
164
+ paths: tuple: List of file/directory paths to check.
165
+ tools: str | None: Comma-separated list of tool names to run.
166
+ tool_options: str | None: Tool-specific configuration options.
167
+ exclude: str | None: Comma-separated patterns of files/dirs to exclude.
168
+ include_venv: bool: Whether to include virtual environment directories.
169
+ output: str | None: Path to output file for results.
170
+ output_format: str: Format for displaying results (table, json, etc).
171
+ group_by: str: How to group issues in output (tool, file, etc).
172
+ ignore_conflicts: bool: Whether to ignore tool configuration conflicts.
173
+ verbose: bool: Whether to show verbose output during execution.
174
+ no_log: bool: Whether to disable logging to file.
175
+
176
+ Returns:
177
+ None: This function does not return a value.
178
+ """
179
+ # Build arguments for the click command
180
+ args: list[str] = []
181
+ if paths:
182
+ args.extend(paths)
183
+ if tools:
184
+ args.extend(["--tools", tools])
185
+ if tool_options:
186
+ args.extend(["--tool-options", tool_options])
187
+ if exclude:
188
+ args.extend(["--exclude", exclude])
189
+ if include_venv:
190
+ args.append("--include-venv")
191
+ if output:
192
+ args.extend(["--output", output])
193
+ if output_format:
194
+ args.extend(["--output-format", output_format])
195
+ if group_by:
196
+ args.extend(["--group-by", group_by])
197
+ if ignore_conflicts:
198
+ args.append("--ignore-conflicts")
199
+ # Removed darglint_timeout and prettier_timeout handling
200
+ if verbose:
201
+ args.append("--verbose")
202
+ if no_log:
203
+ args.append("--no-log")
204
+
205
+ runner = CliRunner()
206
+ result = runner.invoke(check_command, args)
207
+
208
+ if result.exit_code != DEFAULT_EXIT_CODE:
209
+ sys.exit(result.exit_code)
210
+ return None
@@ -0,0 +1,167 @@
1
+ """Format command implementation using simplified Loguru-based approach."""
2
+
3
+ import click
4
+ from click.testing import CliRunner
5
+
6
+ from lintro.utils.tool_executor import run_lint_tools_simple
7
+
8
+ # Constants
9
+ DEFAULT_PATHS: list[str] = ["."]
10
+ DEFAULT_EXIT_CODE: int = 0
11
+ DEFAULT_ACTION: str = "fmt"
12
+
13
+
14
+ @click.command()
15
+ @click.argument("paths", nargs=-1, type=click.Path(exists=True))
16
+ @click.option(
17
+ "--tools",
18
+ default=None,
19
+ help="Comma-separated list of tools to run (e.g., ruff,prettier) or 'all'.",
20
+ )
21
+ @click.option(
22
+ "--tool-options",
23
+ default=None,
24
+ help="Tool-specific options in format tool:option=value,tool2:option=value.",
25
+ )
26
+ @click.option(
27
+ "--exclude",
28
+ default=None,
29
+ help="Comma-separated patterns to exclude from formatting.",
30
+ )
31
+ @click.option(
32
+ "--include-venv",
33
+ is_flag=True,
34
+ default=False,
35
+ help="Include virtual environment directories in formatting.",
36
+ )
37
+ @click.option(
38
+ "--group-by",
39
+ default="auto",
40
+ type=click.Choice(["file", "code", "none", "auto"]),
41
+ help="How to group issues in output.",
42
+ )
43
+ @click.option(
44
+ "--output-format",
45
+ default="grid",
46
+ type=click.Choice(["plain", "grid", "markdown", "html", "json", "csv"]),
47
+ help="Output format for displaying results.",
48
+ )
49
+ @click.option(
50
+ "--verbose",
51
+ "-v",
52
+ is_flag=True,
53
+ default=False,
54
+ help="Enable verbose output with debug information.",
55
+ )
56
+ @click.option(
57
+ "--raw-output",
58
+ is_flag=True,
59
+ default=False,
60
+ help="Show raw tool output instead of formatted output.",
61
+ )
62
+ def format_code(
63
+ paths: tuple[str, ...],
64
+ tools: str | None,
65
+ tool_options: str | None,
66
+ exclude: str | None,
67
+ include_venv: bool,
68
+ group_by: str,
69
+ output_format: str,
70
+ verbose: bool,
71
+ raw_output: bool,
72
+ ) -> None:
73
+ """Format code using configured formatting tools.
74
+
75
+ Runs code formatting tools on the specified paths to automatically fix style issues.
76
+ Uses simplified Loguru-based logging for clean output and proper file logging.
77
+
78
+ Args:
79
+ paths: tuple[str, ...]:
80
+ Paths to format (defaults to current directory if none provided).
81
+ tools: str | None: Specific tools to run, or 'all' for all available tools.
82
+ tool_options: str | None: Tool-specific configuration options.
83
+ exclude: str | None: Patterns to exclude from formatting.
84
+ include_venv: bool: Whether to include virtual environment directories.
85
+ group_by: str: How to group issues in the output display.
86
+ output_format: str: Format for displaying results.
87
+ verbose: bool: Enable detailed debug output.
88
+ raw_output: bool:
89
+ Show raw tool output instead of formatted output.
90
+
91
+ Raises:
92
+ ClickException: If issues are found during formatting.
93
+ """
94
+ # Default to current directory if no paths provided
95
+ if not paths:
96
+ paths = DEFAULT_PATHS
97
+
98
+ # Run with simplified approach
99
+ exit_code: int = run_lint_tools_simple(
100
+ action=DEFAULT_ACTION,
101
+ paths=list(paths),
102
+ tools=tools,
103
+ tool_options=tool_options,
104
+ exclude=exclude,
105
+ include_venv=include_venv,
106
+ group_by=group_by,
107
+ output_format=output_format,
108
+ verbose=verbose,
109
+ raw_output=raw_output,
110
+ )
111
+
112
+ # Exit with appropriate code
113
+ if exit_code != DEFAULT_EXIT_CODE:
114
+ raise click.ClickException("Format found issues")
115
+
116
+
117
+ def format_code_legacy(
118
+ paths: list[str] | None = None,
119
+ tools: str | None = None,
120
+ tool_options: str | None = None,
121
+ exclude: str | None = None,
122
+ include_venv: bool = False,
123
+ group_by: str = "auto",
124
+ output_format: str = "grid",
125
+ verbose: bool = False,
126
+ ) -> None:
127
+ """Programmatic format function for backward compatibility.
128
+
129
+ Args:
130
+ paths: list[str] | None: List of file/directory paths to format.
131
+ tools: str | None: Comma-separated list of tool names to run.
132
+ tool_options: str | None: Tool-specific configuration options.
133
+ exclude: str | None: Comma-separated patterns of files/dirs to exclude.
134
+ include_venv: bool: Whether to include virtual environment directories.
135
+ group_by: str: How to group issues in output (tool, file, etc).
136
+ output_format: str: Format for displaying results (table, json, etc).
137
+ verbose: bool: Whether to show verbose output during execution.
138
+
139
+ Returns:
140
+ None: This function does not return a value.
141
+
142
+ Raises:
143
+ Exception: If format fails for any reason.
144
+ """
145
+ args: list[str] = []
146
+ if paths:
147
+ args.extend(paths)
148
+ if tools:
149
+ args.extend(["--tools", tools])
150
+ if tool_options:
151
+ args.extend(["--tool-options", tool_options])
152
+ if exclude:
153
+ args.extend(["--exclude", exclude])
154
+ if include_venv:
155
+ args.append("--include-venv")
156
+ if group_by:
157
+ args.extend(["--group-by", group_by])
158
+ if output_format:
159
+ args.extend(["--output-format", output_format])
160
+ if verbose:
161
+ args.append("--verbose")
162
+
163
+ runner = CliRunner()
164
+ result = runner.invoke(format_code, args)
165
+ if result.exit_code != DEFAULT_EXIT_CODE:
166
+ raise Exception(f"Format failed: {result.output}")
167
+ return None
@@ -0,0 +1,114 @@
1
+ """List tools command implementation for lintro CLI.
2
+
3
+ This module provides the core logic for the 'list_tools' command.
4
+ """
5
+
6
+ import click
7
+
8
+ from lintro.enums.action import Action
9
+ from lintro.tools import tool_manager
10
+ from lintro.utils.console_logger import get_tool_emoji
11
+
12
+
13
+ @click.command("list-tools")
14
+ @click.option(
15
+ "--output",
16
+ type=click.Path(),
17
+ help="Output file path for writing results",
18
+ )
19
+ @click.option(
20
+ "--show-conflicts",
21
+ is_flag=True,
22
+ help="Show potential conflicts between tools",
23
+ )
24
+ def list_tools_command(
25
+ output,
26
+ show_conflicts,
27
+ ) -> None:
28
+ """List all available tools and their configurations.
29
+
30
+ Args:
31
+ output: Path to output file for writing results.
32
+ show_conflicts: Whether to show potential conflicts between tools.
33
+ """
34
+ list_tools(output=output, show_conflicts=show_conflicts)
35
+
36
+
37
+ def list_tools(
38
+ output: str | None,
39
+ show_conflicts: bool,
40
+ ) -> None:
41
+ """List all available tools.
42
+
43
+ Args:
44
+ output: Output file path.
45
+ show_conflicts: Whether to show potential conflicts between tools.
46
+ """
47
+ available_tools = tool_manager.get_available_tools()
48
+ check_tools = tool_manager.get_check_tools()
49
+ fix_tools = tool_manager.get_fix_tools()
50
+
51
+ output_lines = []
52
+
53
+ # Create header with emojis
54
+ border = "=" * 70
55
+ header_title = "🔧 Available Tools"
56
+ emojis = "🔧 🔧 🔧 🔧 🔧"
57
+ output_lines.append(f"{border}")
58
+ output_lines.append(f"{header_title} {emojis}")
59
+ output_lines.append(f"{border}")
60
+ output_lines.append("")
61
+
62
+ for tool_enum, tool in available_tools.items():
63
+ tool_name = tool_enum.name.lower()
64
+ tool_description = getattr(tool.config, "description", tool.__class__.__name__)
65
+ emoji = get_tool_emoji(tool_name)
66
+
67
+ capabilities: list[str] = []
68
+ if tool_enum in check_tools:
69
+ capabilities.append(Action.CHECK.value)
70
+ if tool_enum in fix_tools:
71
+ capabilities.append(Action.FIX.value)
72
+
73
+ output_lines.append(f"{emoji} {tool_name}: {tool_description}")
74
+ output_lines.append(f" Capabilities: {', '.join(capabilities)}")
75
+
76
+ if (
77
+ show_conflicts
78
+ and hasattr(tool.config, "conflicts_with")
79
+ and tool.config.conflicts_with
80
+ ):
81
+ conflicts = [
82
+ conflict.name.lower()
83
+ for conflict in tool.config.conflicts_with
84
+ if conflict in available_tools
85
+ ]
86
+ if conflicts:
87
+ output_lines.append(f" Conflicts with: {', '.join(conflicts)}")
88
+
89
+ output_lines.append("")
90
+
91
+ # Add summary footer
92
+ summary_border = "-" * 70
93
+ output_lines.append(summary_border)
94
+ output_lines.append(f"📊 Total tools: {len(available_tools)}")
95
+ output_lines.append(f"🔍 Check tools: {len(check_tools)}")
96
+ output_lines.append(f"🔧 Fix tools: {len(fix_tools)}")
97
+ output_lines.append(summary_border)
98
+
99
+ # Format output
100
+ output_text = "\n".join(output_lines)
101
+
102
+ # Print to console using click.echo for consistency
103
+ click.echo(output_text)
104
+
105
+ # Write to file if specified
106
+ if output:
107
+ try:
108
+ with open(output, "w", encoding="utf-8") as f:
109
+ f.write(output_text + "\n")
110
+ success_msg = f"Output written to: {output}"
111
+ click.echo(success_msg)
112
+ except IOError as e:
113
+ error_msg = f"Error writing to file {output}: {e}"
114
+ click.echo(error_msg, err=True)
File without changes
lintro/enums/action.py ADDED
@@ -0,0 +1,29 @@
1
+ """Action/capability enum for tools (check vs. fix)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import StrEnum
6
+
7
+
8
+ class Action(StrEnum):
9
+ """Supported actions a tool can perform."""
10
+
11
+ CHECK = "check"
12
+ FIX = "fix"
13
+
14
+
15
+ def normalize_action(value: str | Action) -> Action:
16
+ """Normalize a raw value to an Action enum.
17
+
18
+ Args:
19
+ value: str or Action to normalize.
20
+
21
+ Returns:
22
+ Action: Normalized enum value.
23
+ """
24
+ if isinstance(value, Action):
25
+ return value
26
+ try:
27
+ return Action(value.lower())
28
+ except Exception:
29
+ return Action.CHECK
@@ -0,0 +1,22 @@
1
+ """Darglint strictness levels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import StrEnum, auto
6
+
7
+
8
+ class DarglintStrictness(StrEnum):
9
+ SHORT = auto()
10
+ LONG = auto()
11
+ FULL = auto()
12
+
13
+
14
+ def normalize_darglint_strictness(
15
+ value: str | DarglintStrictness,
16
+ ) -> DarglintStrictness:
17
+ if isinstance(value, DarglintStrictness):
18
+ return value
19
+ try:
20
+ return DarglintStrictness[value.upper()]
21
+ except Exception:
22
+ return DarglintStrictness.FULL
@@ -0,0 +1,31 @@
1
+ """Grouping strategy enum definitions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import StrEnum, auto
6
+
7
+
8
+ class GroupBy(StrEnum):
9
+ """Supported grouping strategies for presenting issues."""
10
+
11
+ FILE = auto()
12
+ CODE = auto()
13
+ NONE = auto()
14
+ AUTO = auto()
15
+
16
+
17
+ def normalize_group_by(value: str | GroupBy) -> GroupBy:
18
+ """Normalize a raw value to GroupBy enum.
19
+
20
+ Args:
21
+ value: str or GroupBy to normalize.
22
+
23
+ Returns:
24
+ GroupBy: Normalized enum value.
25
+ """
26
+ if isinstance(value, GroupBy):
27
+ return value
28
+ try:
29
+ return GroupBy[value.upper()]
30
+ except Exception:
31
+ return GroupBy.FILE