lintro 0.6.3__py3-none-any.whl → 0.8.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.
Potentially problematic release.
This version of lintro might be problematic. Click here for more details.
- lintro/__init__.py +1 -1
- lintro/cli.py +6 -0
- lintro/enums/__init__.py +1 -0
- lintro/enums/darglint_strictness.py +10 -0
- lintro/enums/hadolint_enums.py +22 -0
- lintro/enums/yamllint_format.py +11 -0
- lintro/exceptions/__init__.py +1 -0
- lintro/formatters/__init__.py +1 -0
- lintro/formatters/core/__init__.py +1 -0
- lintro/formatters/core/output_style.py +11 -0
- lintro/formatters/core/table_descriptor.py +8 -0
- lintro/formatters/styles/csv.py +2 -0
- lintro/formatters/styles/grid.py +2 -0
- lintro/formatters/styles/html.py +2 -0
- lintro/formatters/styles/json.py +2 -0
- lintro/formatters/styles/markdown.py +2 -0
- lintro/formatters/styles/plain.py +2 -0
- lintro/formatters/tools/black_formatter.py +27 -5
- lintro/formatters/tools/darglint_formatter.py +16 -1
- lintro/formatters/tools/hadolint_formatter.py +13 -0
- lintro/formatters/tools/prettier_formatter.py +15 -0
- lintro/formatters/tools/ruff_formatter.py +16 -1
- lintro/formatters/tools/yamllint_formatter.py +14 -1
- lintro/models/__init__.py +1 -0
- lintro/models/core/__init__.py +1 -0
- lintro/models/core/tool_config.py +11 -7
- lintro/parsers/darglint/__init__.py +1 -0
- lintro/parsers/darglint/darglint_issue.py +11 -0
- lintro/parsers/prettier/__init__.py +1 -0
- lintro/parsers/prettier/prettier_issue.py +12 -0
- lintro/parsers/ruff/ruff_parser.py +6 -2
- lintro/parsers/yamllint/__init__.py +1 -0
- lintro/tools/core/__init__.py +1 -0
- lintro/tools/core/tool_base.py +32 -6
- lintro/tools/implementations/__init__.py +1 -0
- lintro/tools/implementations/tool_bandit.py +11 -22
- lintro/tools/implementations/tool_darglint.py +3 -1
- lintro/tools/tool_enum.py +2 -0
- lintro/utils/__init__.py +1 -0
- lintro/utils/ascii_normalize_cli.py +5 -0
- lintro/utils/tool_utils.py +6 -10
- {lintro-0.6.3.dist-info → lintro-0.8.0.dist-info}/METADATA +46 -10
- {lintro-0.6.3.dist-info → lintro-0.8.0.dist-info}/RECORD +47 -47
- {lintro-0.6.3.dist-info → lintro-0.8.0.dist-info}/WHEEL +0 -0
- {lintro-0.6.3.dist-info → lintro-0.8.0.dist-info}/entry_points.txt +0 -0
- {lintro-0.6.3.dist-info → lintro-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {lintro-0.6.3.dist-info → lintro-0.8.0.dist-info}/top_level.txt +0 -0
lintro/__init__.py
CHANGED
lintro/cli.py
CHANGED
|
@@ -9,6 +9,12 @@ from lintro.cli_utils.commands.list_tools import list_tools_command
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class LintroGroup(click.Group):
|
|
12
|
+
"""Custom Click group with enhanced help rendering.
|
|
13
|
+
|
|
14
|
+
This group prints command aliases alongside their canonical names to make
|
|
15
|
+
the CLI help output more discoverable.
|
|
16
|
+
"""
|
|
17
|
+
|
|
12
18
|
def format_commands(
|
|
13
19
|
self,
|
|
14
20
|
ctx: click.Context,
|
lintro/enums/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Enumeration types used throughout the Lintro codebase."""
|
|
@@ -6,6 +6,8 @@ from enum import StrEnum, auto
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class DarglintStrictness(StrEnum):
|
|
9
|
+
"""Strictness levels recognized by Darglint checks."""
|
|
10
|
+
|
|
9
11
|
SHORT = auto()
|
|
10
12
|
LONG = auto()
|
|
11
13
|
FULL = auto()
|
|
@@ -14,6 +16,14 @@ class DarglintStrictness(StrEnum):
|
|
|
14
16
|
def normalize_darglint_strictness(
|
|
15
17
|
value: str | DarglintStrictness,
|
|
16
18
|
) -> DarglintStrictness:
|
|
19
|
+
"""Normalize a strictness value, defaulting to FULL on error.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
value: String or enum member representing strictness.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
DarglintStrictness: Normalized strictness enum value.
|
|
26
|
+
"""
|
|
17
27
|
if isinstance(value, DarglintStrictness):
|
|
18
28
|
return value
|
|
19
29
|
try:
|
lintro/enums/hadolint_enums.py
CHANGED
|
@@ -6,6 +6,8 @@ from enum import StrEnum, auto
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class HadolintFormat(StrEnum):
|
|
9
|
+
"""Supported output formats for Hadolint."""
|
|
10
|
+
|
|
9
11
|
TTY = auto()
|
|
10
12
|
JSON = auto()
|
|
11
13
|
CHECKSTYLE = auto()
|
|
@@ -18,6 +20,8 @@ class HadolintFormat(StrEnum):
|
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
class HadolintFailureThreshold(StrEnum):
|
|
23
|
+
"""Hadolint failure thresholds used to gate exit status."""
|
|
24
|
+
|
|
21
25
|
ERROR = auto()
|
|
22
26
|
WARNING = auto()
|
|
23
27
|
INFO = auto()
|
|
@@ -27,6 +31,15 @@ class HadolintFailureThreshold(StrEnum):
|
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
def normalize_hadolint_format(value: str | HadolintFormat) -> HadolintFormat:
|
|
34
|
+
"""Normalize user input to a HadolintFormat.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
value: Existing enum member or string name of the format.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
HadolintFormat: Canonical enum value, defaulting to ``TTY`` when
|
|
41
|
+
parsing fails.
|
|
42
|
+
"""
|
|
30
43
|
if isinstance(value, HadolintFormat):
|
|
31
44
|
return value
|
|
32
45
|
try:
|
|
@@ -38,6 +51,15 @@ def normalize_hadolint_format(value: str | HadolintFormat) -> HadolintFormat:
|
|
|
38
51
|
def normalize_hadolint_threshold(
|
|
39
52
|
value: str | HadolintFailureThreshold,
|
|
40
53
|
) -> HadolintFailureThreshold:
|
|
54
|
+
"""Normalize user input to a HadolintFailureThreshold.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
value: Existing enum member or string name of the threshold.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
HadolintFailureThreshold: Canonical enum value, defaulting to ``INFO``
|
|
61
|
+
when parsing fails.
|
|
62
|
+
"""
|
|
41
63
|
if isinstance(value, HadolintFailureThreshold):
|
|
42
64
|
return value
|
|
43
65
|
try:
|
lintro/enums/yamllint_format.py
CHANGED
|
@@ -6,6 +6,8 @@ from enum import StrEnum, auto
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class YamllintFormat(StrEnum):
|
|
9
|
+
"""Output styles supported by Yamllint's CLI."""
|
|
10
|
+
|
|
9
11
|
PARSABLE = auto()
|
|
10
12
|
STANDARD = auto()
|
|
11
13
|
COLORED = auto()
|
|
@@ -14,6 +16,15 @@ class YamllintFormat(StrEnum):
|
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
def normalize_yamllint_format(value: str | YamllintFormat) -> YamllintFormat:
|
|
19
|
+
"""Normalize a value to a YamllintFormat enum member.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
value: Existing enum member or string name of the format.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
YamllintFormat: Canonical enum value, defaulting to ``PARSABLE`` when
|
|
26
|
+
parsing fails.
|
|
27
|
+
"""
|
|
17
28
|
if isinstance(value, YamllintFormat):
|
|
18
29
|
return value
|
|
19
30
|
try:
|
lintro/exceptions/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Project-specific exception classes and error helpers."""
|
lintro/formatters/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Formatters for converting tool outputs into human-friendly tables."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core formatting abstractions for tool-agnostic table rendering."""
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
"""Output style abstraction for rendering tabular data.
|
|
2
|
+
|
|
3
|
+
Defines a minimal interface consumed by format-specific implementations.
|
|
4
|
+
"""
|
|
5
|
+
|
|
1
6
|
from abc import ABC, abstractmethod
|
|
2
7
|
from typing import Any
|
|
3
8
|
|
|
4
9
|
|
|
5
10
|
class OutputStyle(ABC):
|
|
11
|
+
"""Abstract base class for output style renderers.
|
|
12
|
+
|
|
13
|
+
Implementations convert tabular data into a concrete textual
|
|
14
|
+
representation (e.g., grid, markdown, plain).
|
|
15
|
+
"""
|
|
16
|
+
|
|
6
17
|
@abstractmethod
|
|
7
18
|
def format(
|
|
8
19
|
self,
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
"""Interfaces for describing table columns and rows for tool issues."""
|
|
2
|
+
|
|
1
3
|
from abc import ABC, abstractmethod
|
|
2
4
|
from typing import Any
|
|
3
5
|
|
|
4
6
|
|
|
5
7
|
class TableDescriptor(ABC):
|
|
8
|
+
"""Describe how to extract tabular data for a tool's issues.
|
|
9
|
+
|
|
10
|
+
Concrete implementations define column ordering and how to map issue
|
|
11
|
+
objects into a list of column values.
|
|
12
|
+
"""
|
|
13
|
+
|
|
6
14
|
@abstractmethod
|
|
7
15
|
def get_columns(self) -> list[str]:
|
|
8
16
|
"""Return the list of column names in order."""
|
lintro/formatters/styles/csv.py
CHANGED
lintro/formatters/styles/grid.py
CHANGED
lintro/formatters/styles/html.py
CHANGED
lintro/formatters/styles/json.py
CHANGED
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from lintro.formatters.core.table_descriptor import TableDescriptor
|
|
6
5
|
from lintro.formatters.styles.csv import CsvStyle
|
|
7
6
|
from lintro.formatters.styles.grid import GridStyle
|
|
8
7
|
from lintro.formatters.styles.html import HtmlStyle
|
|
9
8
|
from lintro.formatters.styles.json import JsonStyle
|
|
10
9
|
from lintro.formatters.styles.markdown import MarkdownStyle
|
|
11
10
|
from lintro.formatters.styles.plain import PlainStyle
|
|
12
|
-
from lintro.parsers.black.black_issue import BlackIssue
|
|
13
11
|
from lintro.utils.path_utils import normalize_file_path_for_display
|
|
14
12
|
|
|
15
13
|
FORMAT_MAP = {
|
|
@@ -22,11 +20,26 @@ FORMAT_MAP = {
|
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
|
|
25
|
-
class BlackTableDescriptor
|
|
23
|
+
class BlackTableDescriptor:
|
|
24
|
+
"""Column layout for Black issues in tabular output."""
|
|
25
|
+
|
|
26
26
|
def get_columns(self) -> list[str]:
|
|
27
|
+
"""Return ordered column headers for Black output rows.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
list[str]: Column names for the formatted table.
|
|
31
|
+
"""
|
|
27
32
|
return ["File", "Message"]
|
|
28
33
|
|
|
29
|
-
def get_rows(self, issues: list
|
|
34
|
+
def get_rows(self, issues: list) -> list[list[str]]:
|
|
35
|
+
"""Return formatted rows for Black issues.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
issues: Parsed Black issues to render.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
list[list[str]]: Table rows with normalized file paths and messages.
|
|
42
|
+
"""
|
|
30
43
|
rows: list[list[str]] = []
|
|
31
44
|
for issue in issues:
|
|
32
45
|
rows.append(
|
|
@@ -38,7 +51,16 @@ class BlackTableDescriptor(TableDescriptor):
|
|
|
38
51
|
return rows
|
|
39
52
|
|
|
40
53
|
|
|
41
|
-
def format_black_issues(issues
|
|
54
|
+
def format_black_issues(issues, format: str) -> str:
|
|
55
|
+
"""Format Black issues according to the chosen style.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
issues: Parsed Black issues.
|
|
59
|
+
format: Output style identifier.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
str: Rendered table string.
|
|
63
|
+
"""
|
|
42
64
|
descriptor = BlackTableDescriptor()
|
|
43
65
|
formatter = FORMAT_MAP.get(format, GridStyle())
|
|
44
66
|
columns = descriptor.get_columns()
|
|
@@ -21,13 +21,28 @@ FORMAT_MAP = {
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class DarglintTableDescriptor(TableDescriptor):
|
|
24
|
+
"""Describe columns and rows for Darglint issues."""
|
|
25
|
+
|
|
24
26
|
def get_columns(self) -> list[str]:
|
|
27
|
+
"""Return column headers for the Darglint issues table.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
list[str]: Column names for the formatted table.
|
|
31
|
+
"""
|
|
25
32
|
return ["File", "Line", "Code", "Message"]
|
|
26
33
|
|
|
27
34
|
def get_rows(
|
|
28
35
|
self,
|
|
29
36
|
issues: list[DarglintIssue],
|
|
30
37
|
) -> list[list[str]]:
|
|
38
|
+
"""Return rows for the Darglint table.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
issues: Parsed Darglint issues to format.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
list[list[str]]: Table rows with normalized path, line, code, message.
|
|
45
|
+
"""
|
|
31
46
|
rows = []
|
|
32
47
|
for issue in issues:
|
|
33
48
|
rows.append(
|
|
@@ -52,7 +67,7 @@ def format_darglint_issues(
|
|
|
52
67
|
format: Output format (plain, grid, markdown, html, json, csv).
|
|
53
68
|
|
|
54
69
|
Returns:
|
|
55
|
-
Formatted string representation of the issues.
|
|
70
|
+
str: Formatted string representation of the issues.
|
|
56
71
|
"""
|
|
57
72
|
descriptor = DarglintTableDescriptor()
|
|
58
73
|
columns = descriptor.get_columns()
|
|
@@ -19,6 +19,11 @@ class HadolintTableDescriptor(TableDescriptor):
|
|
|
19
19
|
"""Describe hadolint issue columns and row extraction."""
|
|
20
20
|
|
|
21
21
|
def get_columns(self) -> list[str]:
|
|
22
|
+
"""Return ordered column headers for the Hadolint table.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
list[str]: Column names for the formatted table.
|
|
26
|
+
"""
|
|
22
27
|
return [
|
|
23
28
|
"File",
|
|
24
29
|
"Line",
|
|
@@ -32,6 +37,14 @@ class HadolintTableDescriptor(TableDescriptor):
|
|
|
32
37
|
self,
|
|
33
38
|
issues: list[HadolintIssue],
|
|
34
39
|
) -> list[list[Any]]:
|
|
40
|
+
"""Return rows for the Hadolint issues table.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
issues: Parsed Hadolint issues to render.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
list[list[Any]]: Table rows with normalized file path and fields.
|
|
47
|
+
"""
|
|
35
48
|
rows: list[list[Any]] = []
|
|
36
49
|
for issue in issues:
|
|
37
50
|
rows.append(
|
|
@@ -21,13 +21,28 @@ FORMAT_MAP = {
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class PrettierTableDescriptor(TableDescriptor):
|
|
24
|
+
"""Describe columns and rows for Prettier issues."""
|
|
25
|
+
|
|
24
26
|
def get_columns(self) -> list[str]:
|
|
27
|
+
"""Return ordered column headers for the Prettier table.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
list[str]: Column names for the formatted table.
|
|
31
|
+
"""
|
|
25
32
|
return ["File", "Line", "Column", "Code", "Message"]
|
|
26
33
|
|
|
27
34
|
def get_rows(
|
|
28
35
|
self,
|
|
29
36
|
issues: list[PrettierIssue],
|
|
30
37
|
) -> list[list[str]]:
|
|
38
|
+
"""Return rows for the Prettier issues table.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
issues: Parsed Prettier issues to render.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
list[list[str]]: Table rows with normalized file path and fields.
|
|
45
|
+
"""
|
|
31
46
|
rows = []
|
|
32
47
|
for issue in issues:
|
|
33
48
|
rows.append(
|
|
@@ -21,13 +21,28 @@ FORMAT_MAP = {
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class RuffTableDescriptor(TableDescriptor):
|
|
24
|
+
"""Describe columns and rows for Ruff issues."""
|
|
25
|
+
|
|
24
26
|
def get_columns(self) -> list[str]:
|
|
27
|
+
"""Return ordered column headers for the Ruff table.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
list[str]: Column names for the formatted table.
|
|
31
|
+
"""
|
|
25
32
|
return ["File", "Line", "Column", "Code", "Message"]
|
|
26
33
|
|
|
27
34
|
def get_rows(
|
|
28
35
|
self,
|
|
29
36
|
issues: list[RuffIssue | RuffFormatIssue],
|
|
30
37
|
) -> list[list[str]]:
|
|
38
|
+
"""Return rows for the Ruff issues table.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
issues: Parsed Ruff issues to render.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
list[list[str]]: Table rows with normalized file path and fields.
|
|
45
|
+
"""
|
|
31
46
|
rows = []
|
|
32
47
|
for issue in issues:
|
|
33
48
|
if isinstance(issue, RuffIssue):
|
|
@@ -69,7 +84,7 @@ def format_ruff_issues(
|
|
|
69
84
|
format: Output format (plain, grid, markdown, html, json, csv).
|
|
70
85
|
|
|
71
86
|
Returns:
|
|
72
|
-
Formatted string (one or two tables depending on format).
|
|
87
|
+
str: Formatted string (one or two tables depending on format).
|
|
73
88
|
"""
|
|
74
89
|
descriptor = RuffTableDescriptor()
|
|
75
90
|
formatter = FORMAT_MAP.get(format, GridStyle())
|
|
@@ -19,6 +19,11 @@ class YamllintTableDescriptor(TableDescriptor):
|
|
|
19
19
|
"""Describe yamllint issue columns and row extraction."""
|
|
20
20
|
|
|
21
21
|
def get_columns(self) -> list[str]:
|
|
22
|
+
"""Return ordered column headers for the Yamllint table.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
list[str]: Column names for the formatted table.
|
|
26
|
+
"""
|
|
22
27
|
return [
|
|
23
28
|
"File",
|
|
24
29
|
"Line",
|
|
@@ -32,6 +37,14 @@ class YamllintTableDescriptor(TableDescriptor):
|
|
|
32
37
|
self,
|
|
33
38
|
issues: list[YamllintIssue],
|
|
34
39
|
) -> list[list[Any]]:
|
|
40
|
+
"""Return rows for the Yamllint issues table.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
issues: Parsed Yamllint issues to render.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
list[list[Any]]: Table rows with normalized file path and fields.
|
|
47
|
+
"""
|
|
35
48
|
rows: list[list[Any]] = []
|
|
36
49
|
for issue in issues:
|
|
37
50
|
rows.append(
|
|
@@ -61,7 +74,7 @@ def format_yamllint_issues(
|
|
|
61
74
|
tool_name: Tool name for JSON metadata.
|
|
62
75
|
|
|
63
76
|
Returns:
|
|
64
|
-
Rendered string for the issues table.
|
|
77
|
+
str: Rendered string for the issues table.
|
|
65
78
|
"""
|
|
66
79
|
descriptor = YamllintTableDescriptor()
|
|
67
80
|
columns = descriptor.get_columns()
|
lintro/models/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Model package containing issue types and configuration structures."""
|
lintro/models/core/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core data models used across tool integrations."""
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Core model for tool configuration used by Lintro tools."""
|
|
2
|
+
|
|
1
3
|
from dataclasses import dataclass, field
|
|
2
4
|
|
|
3
5
|
from lintro.enums.tool_type import ToolType
|
|
@@ -5,15 +7,17 @@ from lintro.enums.tool_type import ToolType
|
|
|
5
7
|
|
|
6
8
|
@dataclass
|
|
7
9
|
class ToolConfig:
|
|
8
|
-
"""Configuration for a
|
|
10
|
+
"""Configuration container for a tool.
|
|
11
|
+
|
|
12
|
+
This dataclass defines the static configuration associated with a tool,
|
|
13
|
+
including its priority, file targeting, type flags, and default options.
|
|
9
14
|
|
|
10
15
|
Attributes:
|
|
11
|
-
priority: int:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
options: dict[str, object]: Tool-specific configuration options
|
|
16
|
+
priority: int: Priority used when ordering tools.
|
|
17
|
+
conflicts_with: list[str]: Names of tools that conflict with this one.
|
|
18
|
+
file_patterns: list[str]: Glob patterns to select applicable files.
|
|
19
|
+
tool_type: ToolType: Bitmask describing tool capabilities.
|
|
20
|
+
options: dict[str, object]: Default tool options applied at runtime.
|
|
17
21
|
"""
|
|
18
22
|
|
|
19
23
|
priority: int = 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Parsing utilities and types for Darglint output."""
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
"""Typed structure representing a single Darglint issue."""
|
|
2
|
+
|
|
1
3
|
from dataclasses import dataclass
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
@dataclass
|
|
5
7
|
class DarglintIssue:
|
|
8
|
+
"""Simple container for Darglint findings.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
file: File path where the issue occurred.
|
|
12
|
+
line: Line number of the issue.
|
|
13
|
+
code: Darglint error code.
|
|
14
|
+
message: Human-readable description of the issue.
|
|
15
|
+
"""
|
|
16
|
+
|
|
6
17
|
file: str
|
|
7
18
|
line: int
|
|
8
19
|
code: str
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Parsing utilities and types for Prettier output."""
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
+
"""Typed structure representing a single Prettier issue."""
|
|
2
|
+
|
|
1
3
|
from dataclasses import dataclass
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
@dataclass
|
|
5
7
|
class PrettierIssue:
|
|
8
|
+
"""Simple container for Prettier findings.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
file: File path where the issue occurred.
|
|
12
|
+
line: Line number, if provided by Prettier.
|
|
13
|
+
code: Tool-specific code identifying the rule.
|
|
14
|
+
message: Human-readable description of the issue.
|
|
15
|
+
column: Column number, if provided by Prettier.
|
|
16
|
+
"""
|
|
17
|
+
|
|
6
18
|
file: str
|
|
7
19
|
line: int | None
|
|
8
20
|
code: str
|
|
@@ -129,8 +129,12 @@ def parse_ruff_format_check_output(output: str) -> list[str]:
|
|
|
129
129
|
if not output:
|
|
130
130
|
return []
|
|
131
131
|
files = []
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
import re
|
|
133
|
+
|
|
134
|
+
ansi_re = re.compile(r"\x1b\[[0-9;]*m")
|
|
135
|
+
for raw in output.splitlines():
|
|
136
|
+
# Strip ANSI color codes for stable parsing across environments
|
|
137
|
+
line = ansi_re.sub("", raw).strip()
|
|
134
138
|
# Ruff format --check output: 'Would reformat: path/to/file.py' or
|
|
135
139
|
# 'Would reformat path/to/file.py'
|
|
136
140
|
if line.startswith("Would reformat: "):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Parsing utilities and types for Yamllint output."""
|
lintro/tools/core/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Base classes and utilities for tool implementations."""
|
lintro/tools/core/tool_base.py
CHANGED
|
@@ -147,6 +147,9 @@ class BaseTool(ABC):
|
|
|
147
147
|
TimeoutExpired: If command times out.
|
|
148
148
|
FileNotFoundError: If command executable is not found.
|
|
149
149
|
"""
|
|
150
|
+
# Validate command arguments for safety prior to execution
|
|
151
|
+
self._validate_subprocess_command(cmd=cmd)
|
|
152
|
+
|
|
150
153
|
try:
|
|
151
154
|
result = subprocess.run( # nosec B603 - args list, shell=False
|
|
152
155
|
cmd,
|
|
@@ -157,7 +160,6 @@ class BaseTool(ABC):
|
|
|
157
160
|
"timeout",
|
|
158
161
|
self._default_timeout,
|
|
159
162
|
),
|
|
160
|
-
check=False,
|
|
161
163
|
cwd=cwd,
|
|
162
164
|
)
|
|
163
165
|
return result.returncode == 0, result.stdout + result.stderr
|
|
@@ -184,6 +186,31 @@ class BaseTool(ABC):
|
|
|
184
186
|
f"Please ensure it is installed and in your PATH.",
|
|
185
187
|
) from e
|
|
186
188
|
|
|
189
|
+
def _validate_subprocess_command(self, cmd: list[str]) -> None:
|
|
190
|
+
"""Validate a subprocess command argument list for safety.
|
|
191
|
+
|
|
192
|
+
Ensures that the command is a non-empty list of strings and that no
|
|
193
|
+
argument contains shell metacharacters that could enable command
|
|
194
|
+
injection when passed to subprocess (even with ``shell=False``).
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
cmd: list[str]: Command and arguments to validate.
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
ValueError: If the command list is empty, contains non-strings,
|
|
201
|
+
or contains unsafe characters.
|
|
202
|
+
"""
|
|
203
|
+
if not cmd or not isinstance(cmd, list):
|
|
204
|
+
raise ValueError("Command must be a non-empty list of strings")
|
|
205
|
+
|
|
206
|
+
unsafe_chars: set[str] = {";", "&", "|", ">", "<", "`", "$", "\\", "\n", "\r"}
|
|
207
|
+
|
|
208
|
+
for arg in cmd:
|
|
209
|
+
if not isinstance(arg, str):
|
|
210
|
+
raise ValueError("All command arguments must be strings")
|
|
211
|
+
if any(ch in arg for ch in unsafe_chars):
|
|
212
|
+
raise ValueError("Unsafe character detected in command argument")
|
|
213
|
+
|
|
187
214
|
def set_options(self, **kwargs) -> None:
|
|
188
215
|
"""Set core options.
|
|
189
216
|
|
|
@@ -233,11 +260,10 @@ class BaseTool(ABC):
|
|
|
233
260
|
self,
|
|
234
261
|
paths: list[str],
|
|
235
262
|
) -> str | None:
|
|
236
|
-
"""Return the common parent directory for the given paths
|
|
237
|
-
applicable.
|
|
263
|
+
"""Return the common parent directory for the given paths.
|
|
238
264
|
|
|
239
265
|
Args:
|
|
240
|
-
paths: list[str]:
|
|
266
|
+
paths: list[str]: Paths to compute a common parent directory for.
|
|
241
267
|
|
|
242
268
|
Returns:
|
|
243
269
|
str | None: Common parent directory path, or None if not applicable.
|
|
@@ -300,10 +326,10 @@ class BaseTool(ABC):
|
|
|
300
326
|
if tool_name in python_tools_prefer_uv:
|
|
301
327
|
if shutil.which(tool_name):
|
|
302
328
|
return [tool_name]
|
|
303
|
-
if shutil.which("uv"):
|
|
304
|
-
return ["uv", "run", tool_name]
|
|
305
329
|
if shutil.which("uvx"):
|
|
306
330
|
return ["uvx", tool_name]
|
|
331
|
+
if shutil.which("uv"):
|
|
332
|
+
return ["uv", "run", tool_name]
|
|
307
333
|
return [tool_name]
|
|
308
334
|
|
|
309
335
|
# Default: prefer direct system executable (node/binary tools like
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Concrete tool integrations (Ruff, Black, Prettier, etc.)."""
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
-
import shutil
|
|
6
5
|
import subprocess # nosec B404 - deliberate, shell disabled
|
|
7
6
|
import tomllib
|
|
8
7
|
from dataclasses import dataclass, field
|
|
@@ -243,15 +242,10 @@ class BanditTool(BaseTool):
|
|
|
243
242
|
Returns:
|
|
244
243
|
list[str]: List of command arguments.
|
|
245
244
|
"""
|
|
246
|
-
#
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
|
|
250
|
-
exec_cmd: list[str] = ["bandit"]
|
|
251
|
-
elif shutil.which("uvx"):
|
|
252
|
-
exec_cmd = ["uvx", "bandit"]
|
|
253
|
-
else:
|
|
254
|
-
exec_cmd = ["bandit"]
|
|
245
|
+
# Resolve executable via BaseTool preferences to ensure reliable
|
|
246
|
+
# execution inside the active environment (prefers 'uv run bandit' when
|
|
247
|
+
# available), falling back to a direct executable.
|
|
248
|
+
exec_cmd: list[str] = self._get_executable_command("bandit")
|
|
255
249
|
|
|
256
250
|
cmd: list[str] = exec_cmd + ["-r"]
|
|
257
251
|
|
|
@@ -367,21 +361,16 @@ class BanditTool(BaseTool):
|
|
|
367
361
|
cmd: list[str] = self._build_check_command(files=rel_files)
|
|
368
362
|
|
|
369
363
|
output: str
|
|
370
|
-
# Run Bandit
|
|
371
|
-
#
|
|
364
|
+
# Run Bandit via the shared safe runner in BaseTool. This enforces
|
|
365
|
+
# argument validation and consistent subprocess handling across tools.
|
|
372
366
|
try:
|
|
373
|
-
|
|
374
|
-
cmd,
|
|
375
|
-
capture_output=True,
|
|
376
|
-
text=True,
|
|
367
|
+
success, combined = self._run_subprocess(
|
|
368
|
+
cmd=cmd,
|
|
377
369
|
timeout=timeout,
|
|
378
370
|
cwd=cwd,
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
stderr_text: str = result.stderr or ""
|
|
383
|
-
output = (stdout_text + "\n" + stderr_text).strip()
|
|
384
|
-
rc: int = result.returncode
|
|
371
|
+
)
|
|
372
|
+
output = (combined or "").strip()
|
|
373
|
+
rc: int = 0 if success else 1
|
|
385
374
|
except subprocess.TimeoutExpired:
|
|
386
375
|
raise
|
|
387
376
|
except Exception as e:
|
|
@@ -136,7 +136,9 @@ class DarglintTool(BaseTool):
|
|
|
136
136
|
Returns:
|
|
137
137
|
list[str]: List of command arguments.
|
|
138
138
|
"""
|
|
139
|
-
|
|
139
|
+
# Prefer running via the active environment (uv run) if available,
|
|
140
|
+
# falling back to a direct executable when necessary.
|
|
141
|
+
cmd: list[str] = self._get_executable_command("darglint")
|
|
140
142
|
|
|
141
143
|
# Add configuration options
|
|
142
144
|
if self.options.get("ignore"):
|
lintro/tools/tool_enum.py
CHANGED
lintro/utils/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Utility package providing helpers for formatting and execution."""
|
|
@@ -32,6 +32,11 @@ def _write_sections(
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def main() -> int:
|
|
35
|
+
"""Normalize ASCII art files based on width/height and alignment.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
int: Zero on success, non-zero when the base directory is missing.
|
|
39
|
+
"""
|
|
35
40
|
parser = argparse.ArgumentParser(description="Normalize ASCII art files.")
|
|
36
41
|
parser.add_argument("files", nargs="*", help="Specific ASCII art files to process")
|
|
37
42
|
parser.add_argument("--width", type=int, default=80)
|
lintro/utils/tool_utils.py
CHANGED
|
@@ -394,21 +394,17 @@ def walk_files_with_excludes(
|
|
|
394
394
|
exclude_patterns: list[str],
|
|
395
395
|
include_venv: bool = False,
|
|
396
396
|
) -> list[str]:
|
|
397
|
-
"""
|
|
398
|
-
specified patterns.
|
|
397
|
+
"""Return files under ``paths`` matching patterns and not excluded.
|
|
399
398
|
|
|
400
399
|
Args:
|
|
401
|
-
paths: list[str]:
|
|
402
|
-
file_patterns: list[str]:
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
["__pycache__", "*.pyc"]).
|
|
406
|
-
include_venv: bool: Whether to include virtual environment directories.
|
|
400
|
+
paths: list[str]: Files or directories to search.
|
|
401
|
+
file_patterns: list[str]: Glob patterns to include.
|
|
402
|
+
exclude_patterns: list[str]: Glob patterns to exclude.
|
|
403
|
+
include_venv: bool: Include virtual environment directories when True.
|
|
407
404
|
|
|
408
405
|
Returns:
|
|
409
|
-
list[str]:
|
|
406
|
+
list[str]: Sorted file paths matching include filters and not excluded.
|
|
410
407
|
"""
|
|
411
|
-
|
|
412
408
|
all_files: list[str] = []
|
|
413
409
|
|
|
414
410
|
for path in paths:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lintro
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: A unified CLI tool for code formatting, linting, and quality assurance
|
|
5
5
|
Author-email: TurboCoder13 <turbocoder13@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -50,21 +50,21 @@ Requires-Dist: toml==0.10.2
|
|
|
50
50
|
Requires-Dist: defusedxml==0.7.1
|
|
51
51
|
Provides-Extra: dev
|
|
52
52
|
Requires-Dist: pytest==8.4.2; extra == "dev"
|
|
53
|
-
Requires-Dist: pytest-cov==
|
|
54
|
-
Requires-Dist: pytest-mock==3.15.
|
|
53
|
+
Requires-Dist: pytest-cov==7.0.0; extra == "dev"
|
|
54
|
+
Requires-Dist: pytest-mock==3.15.1; extra == "dev"
|
|
55
55
|
Requires-Dist: pytest-xdist==3.8.0; extra == "dev"
|
|
56
|
-
Requires-Dist: tox==4.30.
|
|
56
|
+
Requires-Dist: tox==4.30.3; extra == "dev"
|
|
57
57
|
Requires-Dist: allure-pytest==2.15.0; extra == "dev"
|
|
58
58
|
Requires-Dist: ruff; extra == "dev"
|
|
59
59
|
Requires-Dist: mypy; extra == "dev"
|
|
60
60
|
Requires-Dist: coverage-badge==1.1.2; extra == "dev"
|
|
61
|
-
Requires-Dist: python-semantic-release==10.
|
|
61
|
+
Requires-Dist: python-semantic-release==10.4.1; extra == "dev"
|
|
62
62
|
Requires-Dist: assertpy==1.1; extra == "dev"
|
|
63
63
|
Requires-Dist: httpx==0.28.1; extra == "dev"
|
|
64
64
|
Provides-Extra: test
|
|
65
65
|
Requires-Dist: pytest==8.4.2; extra == "test"
|
|
66
|
-
Requires-Dist: pytest-cov==
|
|
67
|
-
Requires-Dist: pytest-mock==3.15.
|
|
66
|
+
Requires-Dist: pytest-cov==7.0.0; extra == "test"
|
|
67
|
+
Requires-Dist: pytest-mock==3.15.1; extra == "test"
|
|
68
68
|
Requires-Dist: pytest-xdist==3.8.0; extra == "test"
|
|
69
69
|
Requires-Dist: assertpy==1.1; extra == "test"
|
|
70
70
|
Provides-Extra: typing
|
|
@@ -88,12 +88,12 @@ Lintro is a unified command-line interface that brings together multiple code qu
|
|
|
88
88
|
[](https://github.com/TurboCoder13/py-lintro/actions/workflows/test-and-coverage.yml?query=branch%3Amain)
|
|
89
89
|
[](https://github.com/TurboCoder13/py-lintro/actions/workflows/ci-lintro-analysis.yml?query=branch%3Amain)
|
|
90
90
|
[](https://github.com/TurboCoder13/py-lintro/actions/workflows/docker-build-publish.yml?query=branch%3Amain)
|
|
91
|
+
[&branch=main>)](https://github.com/TurboCoder13/py-lintro/actions/workflows/sbom-on-main.yml?query=branch%3Amain)
|
|
92
|
+
[&event=push>)](https://github.com/TurboCoder13/py-lintro/actions/workflows/publish-pypi-on-tag.yml?query=event%3Apush)
|
|
91
93
|
[](https://pypi.org/project/lintro/)
|
|
92
94
|
|
|
93
95
|
[](https://github.com/TurboCoder13/py-lintro/actions/workflows/codeql.yml?query=branch%3Amain)
|
|
94
|
-
[](https://scorecard.dev/viewer/?uri=github.com/TurboCoder13/py-lintro)
|
|
95
|
-
|
|
96
|
-
[](https://www.bestpractices.dev/projects/11142)
|
|
96
|
+
[](https://scorecard.dev/viewer/?uri=github.com/TurboCoder13/py-lintro) [](docs/security/assurance.md) [](https://github.com/TurboCoder13/py-lintro/actions/workflows/sbom-on-main.yml) [](https://www.bestpractices.dev/projects/11142)
|
|
97
97
|
|
|
98
98
|
### Why Lintro?
|
|
99
99
|
|
|
@@ -114,6 +114,42 @@ Lintro is a unified command-line interface that brings together multiple code qu
|
|
|
114
114
|
- **Docker support** for containerized environments
|
|
115
115
|
- **CI/CD integration** with GitHub Actions
|
|
116
116
|
|
|
117
|
+
## Security & Compliance
|
|
118
|
+
|
|
119
|
+
Lintro follows modern security best practices and provides comprehensive supply chain transparency:
|
|
120
|
+
|
|
121
|
+
- **SBOM Generation**: Automated Software Bill of Materials on every push to main
|
|
122
|
+
- **Formats**: CycloneDX 1.6 and SPDX 2.3 (industry standards)
|
|
123
|
+
- **Compliance**: Meets Executive Order 14028 requirements for federal software
|
|
124
|
+
- **Download**: [Latest SBOM artifacts](https://github.com/TurboCoder13/py-lintro/actions/workflows/sbom-on-main.yml)
|
|
125
|
+
- **Documentation**: See [Security Assurance](docs/security/assurance.md) for details
|
|
126
|
+
|
|
127
|
+
### What's in the SBOM?
|
|
128
|
+
|
|
129
|
+
The SBOM provides a complete inventory of all dependencies:
|
|
130
|
+
|
|
131
|
+
- All Python packages with exact versions
|
|
132
|
+
- All npm packages (like Prettier)
|
|
133
|
+
- All GitHub Actions dependencies (pinned by SHA)
|
|
134
|
+
- Transitive dependencies
|
|
135
|
+
- License information
|
|
136
|
+
|
|
137
|
+
### For Enterprise Users
|
|
138
|
+
|
|
139
|
+
Download SBOMs for security auditing and compliance:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Download latest SBOM artifacts
|
|
143
|
+
gh run download -R TurboCoder13/py-lintro \
|
|
144
|
+
--name sbom-artifacts \
|
|
145
|
+
$(gh run list -R TurboCoder13/py-lintro \
|
|
146
|
+
-w "Security - SBOM Generation" -L 1 \
|
|
147
|
+
--json databaseId -q '.[0].databaseId')
|
|
148
|
+
|
|
149
|
+
# Scan for vulnerabilities (requires grype)
|
|
150
|
+
grype sbom:main-*-py-lintro-sbom.spdx-2.3.json
|
|
151
|
+
```
|
|
152
|
+
|
|
117
153
|
## Supported Tools
|
|
118
154
|
|
|
119
155
|
| Tool | Language | Auto-fix |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
lintro/__init__.py,sha256=
|
|
1
|
+
lintro/__init__.py,sha256=B9ErHS7va0lt7PY2ZC5FLh58GVYpD6_saGuzvkbnm0U,110
|
|
2
2
|
lintro/__main__.py,sha256=McxM6wEcEeCLBHZs0F8xzT1PxVqJYkjtaPq1_-Nug-0,106
|
|
3
|
-
lintro/cli.py,sha256=
|
|
3
|
+
lintro/cli.py,sha256=0apxBcqVxBZdCeXGMyaSdJYSntMIiCFwPwan1jUmPzM,2520
|
|
4
4
|
lintro/ascii-art/fail.txt,sha256=gshKngSrz5FvJdP6g7lPygpLsLsZZh4etBU_wR7PXOw,56396
|
|
5
5
|
lintro/ascii-art/success.txt,sha256=xhteIXcBvl_1QcFKMIS9CkjjCY8czdf9znP9AiB8oPU,90151
|
|
6
6
|
lintro/cli_utils/__init__.py,sha256=F5P_fY_s-gwNZrnV1bzUOgHGb73QeZG1i-K_kfyJ8Yg,250
|
|
@@ -8,41 +8,41 @@ lintro/cli_utils/commands/__init__.py,sha256=GGT-uG0gQLlHAqkrwfwqfCkD6DUMP4Tq1rg
|
|
|
8
8
|
lintro/cli_utils/commands/check.py,sha256=YnpuiX8-kTADnwxS_mZUPf_SkmqdyqTZFJLTDf7QSQ8,6229
|
|
9
9
|
lintro/cli_utils/commands/format.py,sha256=nEU0Hv28O0RCIp6l-pFcKSzzyLE6fajQCiUYpRyHfzU,5175
|
|
10
10
|
lintro/cli_utils/commands/list_tools.py,sha256=Q-ZXwkkDDZ5pdLFLyxYcKMmWAPNF_vv7N4r8yRCEn3M,3495
|
|
11
|
-
lintro/enums/__init__.py,sha256=
|
|
11
|
+
lintro/enums/__init__.py,sha256=ZwCDematwfGNPdZJN9j-yoGE5SkkoddRhoHz3F9pLMY,61
|
|
12
12
|
lintro/enums/action.py,sha256=3gln8HUNpZzAyAAjQH-cOyW1nKCx9MT6S4rFDAVirdc,597
|
|
13
|
-
lintro/enums/darglint_strictness.py,sha256=
|
|
13
|
+
lintro/enums/darglint_strictness.py,sha256=uzAznuAsEbOAJR4bY4v4pDQOyBVRkLGr6t-B7I-zvcs,762
|
|
14
14
|
lintro/enums/group_by.py,sha256=Eb2rJpeTsPhCK-1xnsyogXrcH_pmNvDZ0dHRK1h4kzM,647
|
|
15
|
-
lintro/enums/hadolint_enums.py,sha256=
|
|
15
|
+
lintro/enums/hadolint_enums.py,sha256=L7Srle5_wEhL5yooawkwbg-u-koBGkECcZiqx2gy24Q,1705
|
|
16
16
|
lintro/enums/output_format.py,sha256=lw3omfjUJUdnrqFjUWVBRSBmWdrxIveS2z2JxFxYPlU,954
|
|
17
17
|
lintro/enums/tool_name.py,sha256=LV09Wpuh2hkEo7Ei5BaIzSwqH8hLGZQ8NmmQOzwqqtI,796
|
|
18
18
|
lintro/enums/tool_type.py,sha256=aa01LmewNr1DRuiHSJ0t5ZH3k933ZLbNYUC9gZXJDfI,829
|
|
19
|
-
lintro/enums/yamllint_format.py,sha256=
|
|
20
|
-
lintro/exceptions/__init__.py,sha256=
|
|
19
|
+
lintro/enums/yamllint_format.py,sha256=XzN9S2lHfVz2OKJgcamlXhR6wK9dW3tSCG-s8iiyjoI,802
|
|
20
|
+
lintro/exceptions/__init__.py,sha256=IZclngSiIhDcihyx_-QhTZ__ISIGI1enJu7ytprcLPc,60
|
|
21
21
|
lintro/exceptions/errors.py,sha256=QnELwMd6yTZVMN7nKRElhxLmxo4JeKtb-HDmVNcZ72M,374
|
|
22
|
-
lintro/formatters/__init__.py,sha256
|
|
23
|
-
lintro/formatters/core/__init__.py,sha256=
|
|
24
|
-
lintro/formatters/core/output_style.py,sha256=
|
|
25
|
-
lintro/formatters/core/table_descriptor.py,sha256=
|
|
22
|
+
lintro/formatters/__init__.py,sha256=-G0RkbV5aTkHqGufasVYDwye8DH0t3iB_6p0Lh_05Ik,73
|
|
23
|
+
lintro/formatters/core/__init__.py,sha256=Rgvun_rjCoP8mKpF6x6kaneai8un_81ViDiKLAW94EQ,70
|
|
24
|
+
lintro/formatters/core/output_style.py,sha256=CuUp3BgL4YhVofKaXWuFtTn0QPHuQJQy1sd-7tbcBNg,795
|
|
25
|
+
lintro/formatters/core/table_descriptor.py,sha256=MJvFU3xDVsl7v0_HCCAtxGKom1dw1faZW_86fOk5aEQ,849
|
|
26
26
|
lintro/formatters/styles/__init__.py,sha256=rRGvbHhZpu09PJs0IbraFn3-yAYBxGVFv81hsnKkjiU,337
|
|
27
|
-
lintro/formatters/styles/csv.py,sha256=
|
|
28
|
-
lintro/formatters/styles/grid.py,sha256=
|
|
29
|
-
lintro/formatters/styles/html.py,sha256=
|
|
30
|
-
lintro/formatters/styles/json.py,sha256=
|
|
31
|
-
lintro/formatters/styles/markdown.py,sha256=
|
|
32
|
-
lintro/formatters/styles/plain.py,sha256=
|
|
27
|
+
lintro/formatters/styles/csv.py,sha256=toQ-XmT-A9T2uwELQAdMPY_lzJbh_WQsmmHQXbEQ2kI,1066
|
|
28
|
+
lintro/formatters/styles/grid.py,sha256=54ZtwHsjitkyEjA6aoHCf3GWkMmBXp4fE3c39bjJITw,2908
|
|
29
|
+
lintro/formatters/styles/html.py,sha256=FVjucFJJ3tSoh9nI1NvjJYThv_oWgiBLk6iM7Z-kyoA,1556
|
|
30
|
+
lintro/formatters/styles/json.py,sha256=bVLyHnoUwEcCD-X8GPdIlg_J2FDhOdJRtMr6XcZC0B8,1964
|
|
31
|
+
lintro/formatters/styles/markdown.py,sha256=OsOjq7bNl0P4j0Pf8eu4PiCLPCoD80rK7vZE27r-LQY,1354
|
|
32
|
+
lintro/formatters/styles/plain.py,sha256=lRBnAFpww9Jscw1_cEehAE1W8wTXU-dSCI0auuhvAbU,1172
|
|
33
33
|
lintro/formatters/tools/__init__.py,sha256=5HxvLscHFl-dYv0h_X6_-rEaszdVU-XPNtL-ZkliGvU,1289
|
|
34
34
|
lintro/formatters/tools/actionlint_formatter.py,sha256=GiUlD7DSW375seiPNLwdX3mOjtcn56T7z7ho4nQzEz8,2812
|
|
35
35
|
lintro/formatters/tools/bandit_formatter.py,sha256=WP7haIWGjIPuGZf1FQ5Ixi5DKIySHGdX-L7hZcKnFuw,3093
|
|
36
|
-
lintro/formatters/tools/black_formatter.py,sha256=
|
|
37
|
-
lintro/formatters/tools/darglint_formatter.py,sha256=
|
|
38
|
-
lintro/formatters/tools/hadolint_formatter.py,sha256=
|
|
39
|
-
lintro/formatters/tools/prettier_formatter.py,sha256=
|
|
40
|
-
lintro/formatters/tools/ruff_formatter.py,sha256=
|
|
41
|
-
lintro/formatters/tools/yamllint_formatter.py,sha256=
|
|
42
|
-
lintro/models/__init__.py,sha256=
|
|
43
|
-
lintro/models/core/__init__.py,sha256=
|
|
36
|
+
lintro/formatters/tools/black_formatter.py,sha256=YTe0Zc82p8cWwlq03bRaSJKOT8iHqXuGe2pR7aFhuB4,2092
|
|
37
|
+
lintro/formatters/tools/darglint_formatter.py,sha256=owYIP3QxtTantBwfd4w1GVfaRiaHFXSynxAntSKw7IU,2649
|
|
38
|
+
lintro/formatters/tools/hadolint_formatter.py,sha256=OWc2BYae31U2TdNcxXkGl0W6fTjVWkkaJV57X4l4jRw,2995
|
|
39
|
+
lintro/formatters/tools/prettier_formatter.py,sha256=GYAyHppot5aG_pWF8QHz5GmWqmqgZwE6UmcUQZFesWE,2915
|
|
40
|
+
lintro/formatters/tools/ruff_formatter.py,sha256=DzH-gs-3IhUFQ6cT6rgVxW1RVNVkGo2jrrEZ4Kx-MS8,4445
|
|
41
|
+
lintro/formatters/tools/yamllint_formatter.py,sha256=oEwkU-I4Upfc8--KAgfVAPSyYbeqkdsDXucxj3OwjIA,3093
|
|
42
|
+
lintro/models/__init__.py,sha256=E6tU5BnnaRWyMEf2cdiN_C3nvbRlWDfblKHrK0is7IU,73
|
|
43
|
+
lintro/models/core/__init__.py,sha256=mevoEG547VTotUsgyocEB72OknnGhExNWcfel7ZPLnI,54
|
|
44
44
|
lintro/models/core/tool.py,sha256=TWkVV_KOYziqCdq_f3Goft3PKWKByitsQ2VFiX6MVHM,2594
|
|
45
|
-
lintro/models/core/tool_config.py,sha256=
|
|
45
|
+
lintro/models/core/tool_config.py,sha256=FCfKQ_bz2yBg_FJ5xEud7TdF0PZ3fPp1Yjty02rbHR8,1004
|
|
46
46
|
lintro/models/core/tool_result.py,sha256=z5fexuCBt1ir0hvzojxVX-Abt6MNIT7_JvH5oyW_FlI,1319
|
|
47
47
|
lintro/parsers/__init__.py,sha256=53UA1LuS21BL4xj8i81Qb59dKXe3jCFLBrDVqvvNHVQ,288
|
|
48
48
|
lintro/parsers/actionlint/__init__.py,sha256=N953d0kbJEOZE9cG4eq9BjiSErdk10GMrngV_tKjLvo,33
|
|
@@ -50,47 +50,47 @@ lintro/parsers/actionlint/actionlint_issue.py,sha256=H_BQr04KAGHpVp1qKqETcWLi3i-
|
|
|
50
50
|
lintro/parsers/actionlint/actionlint_parser.py,sha256=FAovzY877UeaDj7ZHb0zy6Y_hsidWS6UR1O8KCYVISU,1889
|
|
51
51
|
lintro/parsers/black/black_issue.py,sha256=RwrT7n8aw4Nybakv83eXoeUxZlDtHwicWKNfrHYIYOg,507
|
|
52
52
|
lintro/parsers/black/black_parser.py,sha256=mCbEy4aTRtxC_SKKPNK6hThGEu8C0m9EnliFW__Sa3Y,2958
|
|
53
|
-
lintro/parsers/darglint/__init__.py,sha256=
|
|
54
|
-
lintro/parsers/darglint/darglint_issue.py,sha256=
|
|
53
|
+
lintro/parsers/darglint/__init__.py,sha256=r2ilRjf8WdHOvXIGsg4SmtYkRUR76DowWLA_n9sIOV0,55
|
|
54
|
+
lintro/parsers/darglint/darglint_issue.py,sha256=Gc07-PGvv4Kn4X85tnACLYB5FygNPthEe3fYodOaFoA,444
|
|
55
55
|
lintro/parsers/darglint/darglint_parser.py,sha256=pbIGnmHVKjf8OaxvhQbDWWXAFZEictb3FfuhoGv_I00,2046
|
|
56
56
|
lintro/parsers/hadolint/__init__.py,sha256=vU33M_cj6fyg7aqZthz8MFUMfBIshX_Nx3DNuQmbHD4,30
|
|
57
57
|
lintro/parsers/hadolint/hadolint_issue.py,sha256=VlTzTPHcluFZihFL-Tkg7UuXp1fQcD03eDCH0sr1qHU,582
|
|
58
58
|
lintro/parsers/hadolint/hadolint_parser.py,sha256=Q7Hf6sL45s38O3C9dbBYzOpDlb0KGFj0U3Yry_ixdK8,1810
|
|
59
|
-
lintro/parsers/prettier/__init__.py,sha256=
|
|
60
|
-
lintro/parsers/prettier/prettier_issue.py,sha256=
|
|
59
|
+
lintro/parsers/prettier/__init__.py,sha256=jH8yEsh_X6TpwJs1V1cN1AmbDuQwQ9qWA-_dk0R9jOA,55
|
|
60
|
+
lintro/parsers/prettier/prettier_issue.py,sha256=DKxV9LXxAB-CxvOsbWVEAmfpXQJvd4ikHKGyMrg1Y60,569
|
|
61
61
|
lintro/parsers/prettier/prettier_parser.py,sha256=lH50rhFHbWWLH50CiTlyIvjgbx9vz1hiIdtxEXi7uJw,2043
|
|
62
62
|
lintro/parsers/ruff/__init__.py,sha256=1oT00c82qKfveRqa4FnSedAEQjQVrb9BspJEUQJn-Kk,26
|
|
63
63
|
lintro/parsers/ruff/ruff_issue.py,sha256=96ht6YWImOBiRTo0ATlM1PvVhgIwFiuN8810emm9nXo,1142
|
|
64
|
-
lintro/parsers/ruff/ruff_parser.py,sha256=
|
|
65
|
-
lintro/parsers/yamllint/__init__.py,sha256=
|
|
64
|
+
lintro/parsers/ruff/ruff_parser.py,sha256=DRGzpf55OnNJCTO01RSFK4GXr6Lav-_JzACdqDesuj0,4722
|
|
65
|
+
lintro/parsers/yamllint/__init__.py,sha256=ZZtw7Ref1EAbY-IwSz2UxJauGak6sKO10pfYsdE_sV8,55
|
|
66
66
|
lintro/parsers/yamllint/yamllint_issue.py,sha256=jWawdGUiTI1HADbhg8yEdZfC6yHcmk9FDzpr3PBUPBg,608
|
|
67
67
|
lintro/parsers/yamllint/yamllint_parser.py,sha256=ol44xhJcspnGIsEta8vVv1xi-sIbpB12CovmT94QFmQ,1947
|
|
68
68
|
lintro/tools/__init__.py,sha256=S-L_x7Hzp-Ja-QezupEUwF6-uhRl4ZXSIpRx59jvsaA,1410
|
|
69
|
-
lintro/tools/tool_enum.py,sha256=
|
|
70
|
-
lintro/tools/core/__init__.py,sha256=
|
|
71
|
-
lintro/tools/core/tool_base.py,sha256=
|
|
69
|
+
lintro/tools/tool_enum.py,sha256=RkJcfEpM_lFWp2y1rFqZdr3qOzYVcSoVBt3XVbtO4Sg,926
|
|
70
|
+
lintro/tools/core/__init__.py,sha256=eUbc-DlpOcFaG_gKzy-veaOQAOkC5-OuItxI--p6I9c,59
|
|
71
|
+
lintro/tools/core/tool_base.py,sha256=e0t7wPpL5dabs4EEE4C0DmqoMGE66ynWRg-WaLAcXsA,13485
|
|
72
72
|
lintro/tools/core/tool_manager.py,sha256=yKQONy17t7-fq1k9dkrMk6lZaAvaSwp7-JcvJFZMoYc,5103
|
|
73
|
-
lintro/tools/implementations/__init__.py,sha256=
|
|
73
|
+
lintro/tools/implementations/__init__.py,sha256=7DX7vWmRUVGYgrB2Rx1IbKpLWfXfVDLiOfz-UX2Crzs,64
|
|
74
74
|
lintro/tools/implementations/tool_actionlint.py,sha256=7b1pUxs9Ln6KmoLiRQBmyDeq9SmgZ08e0DxleM9NEt8,5466
|
|
75
|
-
lintro/tools/implementations/tool_bandit.py,sha256=
|
|
75
|
+
lintro/tools/implementations/tool_bandit.py,sha256=5HhwwHTmXiOlxK9UlfmnGqEtHJnMkD8ryiVHI_AN3s0,15523
|
|
76
76
|
lintro/tools/implementations/tool_black.py,sha256=x1U6NhdRxxYE5Tmvh-LoxcWtIkwHceeJWMUROa9tAJ4,9680
|
|
77
|
-
lintro/tools/implementations/tool_darglint.py,sha256=
|
|
77
|
+
lintro/tools/implementations/tool_darglint.py,sha256=1G_gxjhkFNNCVCSkMDAgicYEZJ6JcI_NGX47Sg3a1vM,9561
|
|
78
78
|
lintro/tools/implementations/tool_hadolint.py,sha256=NfHLoThp23V-n5chSfrBZetleXsRR4oYxkLxOkJxU0g,11479
|
|
79
79
|
lintro/tools/implementations/tool_prettier.py,sha256=tTw3yEn6RR2rCBoZdeDWy6r06Sfd_jCR2fLCBj4MDoY,9783
|
|
80
80
|
lintro/tools/implementations/tool_ruff.py,sha256=8WIpOKSc6HmuvEFCWgTqBX9X4T3MSD-RKesv4bs2lpQ,25361
|
|
81
81
|
lintro/tools/implementations/tool_yamllint.py,sha256=0powR9F3FkIq-b7PI0-XWdh7nx7rR3HVMtvEaz_NWeA,8831
|
|
82
|
-
lintro/utils/__init__.py,sha256=
|
|
83
|
-
lintro/utils/ascii_normalize_cli.py,sha256=
|
|
82
|
+
lintro/utils/__init__.py,sha256=mUAkJXnTb91theOR_ue6FfGHtuSm3C466T_SH_KoWRE,70
|
|
83
|
+
lintro/utils/ascii_normalize_cli.py,sha256=Rlasrsy9FShCKGJ_9ti4VxJGP-I05vAtTmNMENbo_a4,2575
|
|
84
84
|
lintro/utils/config.py,sha256=3AVwNAteT-enN6Ica8jJbPwEFO94i4F7uWiEA1HSpJY,1427
|
|
85
85
|
lintro/utils/console_logger.py,sha256=N0n5LomG6MDqu4tSPbmhBsIB6lzpRl5M53tZx6EoF4k,33104
|
|
86
86
|
lintro/utils/formatting.py,sha256=khC9hYBva5xqBV1IqNcivRH9gRdvWw6u6mh2TZLTy7E,5346
|
|
87
87
|
lintro/utils/output_manager.py,sha256=oIE0g8LNVQcWSQOb1MbDVqGYPrOjBGuUZ4R80M1RevQ,10213
|
|
88
88
|
lintro/utils/path_utils.py,sha256=NJP3vjVDcRBgUHtYNrpL0tRa0Sc3oQhGX3_2WWzdZE4,1395
|
|
89
89
|
lintro/utils/tool_executor.py,sha256=8-m7nQKLRlKHBTvzT7iLmaHYZ3-2s0t4zUbC-py8-H8,26204
|
|
90
|
-
lintro/utils/tool_utils.py,sha256=
|
|
91
|
-
lintro-0.
|
|
92
|
-
lintro-0.
|
|
93
|
-
lintro-0.
|
|
94
|
-
lintro-0.
|
|
95
|
-
lintro-0.
|
|
96
|
-
lintro-0.
|
|
90
|
+
lintro/utils/tool_utils.py,sha256=DIdebZxdUBhomuBKSezfojNOmEZyP7KtGifz1EX1qZo,15746
|
|
91
|
+
lintro-0.8.0.dist-info/licenses/LICENSE,sha256=CwaAnyD2psonDBBJjbqFUz00W8nQw-FGDlEGZReUV6A,1069
|
|
92
|
+
lintro-0.8.0.dist-info/METADATA,sha256=LBm_yVmQmeBQO1lDzfhsnPMXGoup_T-5u6o-KeFQ6CM,16029
|
|
93
|
+
lintro-0.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
94
|
+
lintro-0.8.0.dist-info/entry_points.txt,sha256=SYSk35jFyNLEHyrofSJsRv4qFN9NsT4VWSbvnTS9ov0,43
|
|
95
|
+
lintro-0.8.0.dist-info/top_level.txt,sha256=_D-7eyV6gNBOoIwHuf_h60wN_RWiw8GxB430Il9VKhU,7
|
|
96
|
+
lintro-0.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|