pyright-to-gitlab 1.1.0__py3-none-any.whl → 1.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyright-to-gitlab
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Convert Pyright JSON output to GitLab CI/CD format
5
5
  Project-URL: homepage, https://github.com/schollm/pyright-to-gitlab/
6
6
  Project-URL: repository, https://github.com/schollm/pyright-to-gitlab/
@@ -12,7 +12,6 @@ Keywords: ci/cd,gitlab,pyright
12
12
  Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Programming Language :: Python :: 3.7
16
15
  Classifier: Programming Language :: Python :: 3.8
17
16
  Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
@@ -24,12 +23,21 @@ Classifier: Topic :: Software Development
24
23
  Classifier: Topic :: Software Development :: Testing
25
24
  Classifier: Topic :: Utilities
26
25
  Classifier: Typing :: Typed
27
- Requires-Python: >=3.6
26
+ Requires-Python: >=3.8
28
27
  Description-Content-Type: text/markdown
29
28
 
30
29
  # pyright to gitlab
31
- Simple zero-dependency Python script to convert a pyright --outputjson to a gitlab
32
- code-quality report.
30
+
31
+ [![PyPI version](https://img.shields.io/pypi/v/pyright-to-gitlab.svg)](https://pypi.org/project/pyright-to-gitlab)
32
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyright-to-gitlab.svg)](https://pypi.org/project/pyright-to-gitlab)
33
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
34
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
35
+ [![Typing: typed](https://img.shields.io/badge/typing-typed-blue.svg)](https://github.com/python/mypy)
36
+
37
+ Simple Python tool to convert Pyright JSON output to GitLab Code Quality report format.
38
+
39
+ **Zero runtime dependencies** - Pure Python implementation using only the standard library.
40
+
33
41
 
34
42
  ## Usage
35
43
  Run the script with the path to the pyright output file:
@@ -0,0 +1,6 @@
1
+ pyright_to_gitlab.py,sha256=6b1sRM7aYWQShpWpAxmz5ANYOZla6-wEOxaZba20f6o,5794
2
+ pyright_to_gitlab-1.2.0.dist-info/METADATA,sha256=R__O7qdhzXfc6Vos3LTzr2q-BNceCWCL1LFpBCEdEoQ,2632
3
+ pyright_to_gitlab-1.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
4
+ pyright_to_gitlab-1.2.0.dist-info/entry_points.txt,sha256=0RnHrvYlZf3zD9BRTVQL564gF_fSuwF5IP13OB18540,61
5
+ pyright_to_gitlab-1.2.0.dist-info/licenses/LICENSE,sha256=tY29-MdtyUNoC3XN4IBzu_jxmb8U82z9UvLkQJuBiJM,1070
6
+ pyright_to_gitlab-1.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pyright-to-gitlab = pyright_to_gitlab:main
pyright_to_gitlab.py CHANGED
@@ -1,50 +1,147 @@
1
1
  """Convert pyright.json output to GitLab Code Quality report format."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import argparse
4
6
  import hashlib
5
7
  import json
6
8
  import sys
7
9
  import textwrap
8
- from typing import TextIO, cast
10
+ from typing import Literal, TextIO, TypedDict
11
+
12
+
13
+ ### Typing for PyRight Issue
14
+ class PyrightRangeElement(TypedDict):
15
+ """Pyright Range Element (part of Range)."""
16
+
17
+ line: int
18
+ character: int
19
+
20
+
21
+ class PyrightRange(TypedDict):
22
+ """Pyright Range (Part of Issue)."""
23
+
24
+ start: PyrightRangeElement
25
+ end: PyrightRangeElement
26
+
27
+
28
+ class PyrightIssue(TypedDict):
29
+ """Single Pyright Issue.
30
+
31
+ Note: 'rule' field is optional in practice but marked as required in type hints.
32
+ Runtime code handles this with defensive .get() calls.
33
+ """
34
+
35
+ file: str
36
+ severity: Literal["error", "warning", "information"]
37
+ message: str
38
+ rule: str # Optional in practice, handled via .get() at runtime
39
+ range: PyrightRange
40
+
41
+
42
+ ### Typing for Gitlab Issue
43
+ class GitlabIssuePositionLocation(TypedDict):
44
+ """Single Gitlab Position (Part of Position)."""
45
+
46
+ line: int
47
+ column: int
48
+
49
+
50
+ class GitlabIssuePositions(TypedDict):
51
+ """Gitlab ranged Position within a file (Part of Location)."""
52
+
53
+ begin: GitlabIssuePositionLocation
54
+ end: GitlabIssuePositionLocation
55
+
9
56
 
57
+ class GitlabIssueLocation(TypedDict):
58
+ """Gitlab location (Part of Issue)."""
10
59
 
60
+ path: str
61
+ positions: GitlabIssuePositions
62
+
63
+
64
+ class GitlabIssue(TypedDict):
65
+ """Single Gitlab Issue."""
66
+
67
+ description: str
68
+ severity: Literal["major", "minor"]
69
+ fingerprint: str
70
+ check_name: str
71
+ location: GitlabIssueLocation
72
+
73
+
74
+ ### Functions
11
75
  def _pyright_to_gitlab(input_: TextIO, prefix: str = "") -> str:
12
76
  """Convert pyright.json output to GitLab Code Quality report format.
13
77
 
78
+ Line numbers from Pyright are passed through unchanged (0-based per LSP spec).
79
+ GitLab expects the same format, so no conversion is needed.
80
+
14
81
  :arg prefix: A string to prepend to each file path in the output.
15
82
  This is useful if the application is in a subdirectory of the repository.
16
83
  :return: JSON of issues in GitLab Code Quality report format.
84
+ :raises ValueError: If input is not a JSON object.
85
+ :raises TypeError: If input JSON is not an object.
17
86
 
18
87
  Pyright format at https://github.com/microsoft/pyright/blob/main/docs/command-line.md
19
88
  Gitlab format at https://docs.gitlab.com/ci/testing/code_quality/#code-quality-report-format
20
89
  """
21
- data = cast("dict", json.load(input_))
22
-
23
- issues = []
24
- for issue in data.get("generalDiagnostics", []):
25
- file = issue["file"]
26
- start, end = issue["range"]["start"], issue["range"]["end"]
27
- rule = "pyright: " + issue.get("rule", "")
28
- severity = "major" if issue["severity"] == "error" else "minor"
29
- # unique fingerprint
30
- fp_str = "--".join([str(start), str(end), rule])
31
-
32
- issues.append(
33
- {
34
- "description": issue["message"],
35
- "severity": severity,
36
- "fingerprint": hashlib.sha3_224(fp_str.encode()).hexdigest(),
37
- "check_name": rule,
38
- "location": {
39
- "path": f"{prefix}{file}",
40
- "positions": {
41
- "begin": {"line": start["line"], "column": start["character"]},
42
- "end": {"line": end["line"], "column": end["character"]},
43
- },
44
- },
45
- }
46
- )
47
- return json.dumps(issues, indent=2)
90
+ try:
91
+ data = json.load(input_)
92
+ except json.JSONDecodeError as e:
93
+ err_msg = f"Invalid JSON input: {e}"
94
+ raise ValueError(err_msg) from e
95
+
96
+ if not isinstance(data, dict):
97
+ err_msg = "Input must be a JSON object"
98
+ raise TypeError(err_msg)
99
+
100
+ return json.dumps(
101
+ [
102
+ _pyright_issue_to_gitlab(issue, prefix)
103
+ for issue in data.get("generalDiagnostics", [])
104
+ ],
105
+ indent=2,
106
+ )
107
+
108
+
109
+ def _pyright_issue_to_gitlab(issue: PyrightIssue, prefix: str) -> GitlabIssue:
110
+ """Convert a single issue to gitlab.
111
+
112
+ Uses defensive .get() with defaults to handle missing optional fields.
113
+ File path defaults to '<anonymous>' and missing rule to 'unknown'.
114
+
115
+ :param issue: A pyright single issue.
116
+ :param prefix: The path prefix.
117
+ :returns: A gitlab single issue.
118
+ """
119
+ start, end = (
120
+ issue.get("range", {}).get("start", {}),
121
+ issue.get("range", {}).get("end", {}),
122
+ )
123
+ rule = "pyright: " + issue.get("rule", "unknown")
124
+ # Unique fingerprint including file path to prevent collisions across files
125
+ fp_str = "--".join([issue.get("file", "<anonymous>"), str(start), str(end), rule])
126
+
127
+ return GitlabIssue(
128
+ description=issue.get("message", ""),
129
+ severity="major" if issue.get("severity") == "error" else "minor",
130
+ # Any hash function really works, does not have to be cryptographic.
131
+ fingerprint=hashlib.sha3_224(fp_str.encode()).hexdigest(),
132
+ check_name=rule,
133
+ location=GitlabIssueLocation(
134
+ path=f"{prefix}{issue['file']}" if "file" in issue else "<anonymous>",
135
+ positions=GitlabIssuePositions(
136
+ begin=GitlabIssuePositionLocation(
137
+ line=start.get("line", 0), column=start.get("character", 0)
138
+ ),
139
+ end=GitlabIssuePositionLocation(
140
+ line=end.get("line", 0), column=end.get("character", 0)
141
+ ),
142
+ ),
143
+ ),
144
+ )
48
145
 
49
146
 
50
147
  def main() -> None:
@@ -1,6 +0,0 @@
1
- pyright_to_gitlab.py,sha256=i_54FlXg4RD1_1dr5Kq6onIAua2zRsi9hs_uejB_SK0,3150
2
- pyright_to_gitlab-1.1.0.dist-info/METADATA,sha256=9WGRB8rUH9ylhs98la_TMihlgQ6VNBe_gTAtrFOGjJk,2034
3
- pyright_to_gitlab-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
4
- pyright_to_gitlab-1.1.0.dist-info/entry_points.txt,sha256=MbNff91bPuO2XhW0P03N9O1Z7xtlr3x9duU5BftRbZo,60
5
- pyright_to_gitlab-1.1.0.dist-info/licenses/LICENSE,sha256=tY29-MdtyUNoC3XN4IBzu_jxmb8U82z9UvLkQJuBiJM,1070
6
- pyright_to_gitlab-1.1.0.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- pyrigh-to-gitlab = pyright_to_gitlab:main