pre-commit-localupdate 0.4.0__tar.gz → 0.5.0__tar.gz

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.
Files changed (26) hide show
  1. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/PKG-INFO +44 -27
  2. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/README.md +41 -25
  3. pre_commit_localupdate-0.5.0/pre_commit_localupdate/__init__.py +1 -0
  4. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/pre_commit_localupdate/__main__.py +11 -3
  5. pre_commit_localupdate-0.5.0/pre_commit_localupdate/cli.py +75 -0
  6. pre_commit_localupdate-0.5.0/pre_commit_localupdate/io.py +121 -0
  7. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/pre_commit_localupdate/logs.py +5 -1
  8. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/pre_commit_localupdate/packages/golang.py +22 -38
  9. pre_commit_localupdate-0.5.0/pre_commit_localupdate/packages/julia.py +111 -0
  10. pre_commit_localupdate-0.5.0/pre_commit_localupdate/packages/node.py +85 -0
  11. pre_commit_localupdate-0.5.0/pre_commit_localupdate/packages/package.py +63 -0
  12. pre_commit_localupdate-0.5.0/pre_commit_localupdate/packages/python.py +79 -0
  13. pre_commit_localupdate-0.5.0/pre_commit_localupdate/packages/rust.py +89 -0
  14. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/pre_commit_localupdate/pre_commit_config.py +51 -59
  15. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/pyproject.toml +3 -2
  16. pre_commit_localupdate-0.4.0/pre_commit_localupdate/__init__.py +0 -1
  17. pre_commit_localupdate-0.4.0/pre_commit_localupdate/cli.py +0 -36
  18. pre_commit_localupdate-0.4.0/pre_commit_localupdate/io.py +0 -43
  19. pre_commit_localupdate-0.4.0/pre_commit_localupdate/packages/julia.py +0 -99
  20. pre_commit_localupdate-0.4.0/pre_commit_localupdate/packages/node.py +0 -98
  21. pre_commit_localupdate-0.4.0/pre_commit_localupdate/packages/package.py +0 -41
  22. pre_commit_localupdate-0.4.0/pre_commit_localupdate/packages/python.py +0 -86
  23. pre_commit_localupdate-0.4.0/pre_commit_localupdate/packages/rust.py +0 -103
  24. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/LICENSE +0 -0
  25. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/pre_commit_localupdate/error.py +0 -0
  26. {pre_commit_localupdate-0.4.0 → pre_commit_localupdate-0.5.0}/pre_commit_localupdate/packages/__init__.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pre-commit-localupdate
3
- Version: 0.4.0
4
- Summary: A CLI tool to automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in pre-commit config files.
3
+ Version: 0.5.0
4
+ Summary: A CLI tool to automatically update additional dependencies within local hooks in pre-commit config files.
5
5
  Author: M. Farzalipour Tabriz
6
6
  Classifier: Development Status :: 3 - Alpha
7
7
  Classifier: Environment :: Console
@@ -11,11 +11,12 @@ Project-URL: source, https://gitlab.mpcdf.mpg.de/tbz/pre-commit-localupdate.git
11
11
  Requires-Python: <3.15,>=3.11
12
12
  Requires-Dist: requests>=2.32.5
13
13
  Requires-Dist: ruamel-yaml>=0.19.1
14
+ Requires-Dist: packaging>=26.0
14
15
  Description-Content-Type: text/markdown
15
16
 
16
17
  # pre-commit-localupdate
17
18
 
18
- A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, Rust, Go, and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
19
+ A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
19
20
 
20
21
  ## Installation
21
22
 
@@ -31,22 +32,27 @@ To check and update the `additional_dependencies` in your `.pre-commit-config.ya
31
32
  pre-commit-localupdate
32
33
  ```
33
34
 
34
- By default, the tool looks for `.pre-commit-config.yaml` in the current directory. To specify a custom file path, use the `-c` or `--config` argument:
35
-
36
- ```shell
37
- pre-commit-localupdate --config path/to/.pre-commit-config.yaml
38
- ```
39
-
40
- To check the dependencies without updating, use the `--dry-run` flag. The command will exit with a non-zero status code if any package needs updating:
41
-
42
- ```shell
43
- pre-commit-localupdate --dry-run
44
- ```
45
-
46
- To get debug output use `--debug` flag:
47
-
48
- ```shell
49
- pre-commit-localupdate --debug
35
+ All options:
36
+
37
+ ```text
38
+ usage: pre-commit-localupdate [-h] [--debug] [--dry-run] [-c PRE-COMMIT-CONFIG] [--timeout TIMEOUT]
39
+ [--indent-mapping INDENT_MAPPING] [--indent-sequence INDENT_SEQUENCE]
40
+ [--indent-offset INDENT_OFFSET] [--line-width LINE_WIDTH] [--version]
41
+
42
+ Automatically update additional dependencies within local hooks in a pre-commit config file.
43
+
44
+ options:
45
+ -h, --help show this help message and exit
46
+ --debug enable debug logging (default: False)
47
+ --dry-run dry run mode. Do not update the file and exit with a non-zero code if the
48
+ configuration file require an update. (default: False)
49
+ -c, --config PRE-COMMIT-CONFIG pre-commit config file path (default: .pre-commit-config.yaml)
50
+ --timeout TIMEOUT connection timeout in seconds (default: 10)
51
+ --indent-mapping INDENT_MAPPING YAML indentation for mappings (default: 2)
52
+ --indent-sequence INDENT_SEQUENCE YAML indentation for sequences (default: 4)
53
+ --indent-offset INDENT_OFFSET YAML indentation offset (default: 2)
54
+ --line-width LINE_WIDTH maximum line width (default: 80)
55
+ --version show program's version number and exit
50
56
  ```
51
57
 
52
58
  ## Example
@@ -69,7 +75,7 @@ repos:
69
75
  # All comment are preserved
70
76
  - id: black
71
77
  name: black
72
- description: "Long strings are automatically folded into multilines by ruamel-yaml library!"
78
+ description: "Length of strings is automatically adjusted based on the value of --line-width"
73
79
  entry: black
74
80
  language: python
75
81
  minimum_pre_commit_version: 2.9.2
@@ -83,7 +89,7 @@ repos:
83
89
 
84
90
  - id: julia-format
85
91
  name: format julia code
86
- description: Run `JuliaFormatter.jl` against Julia source files
92
+ description: Unicodeテキストは保持されます。
87
93
  language: julia
88
94
  types: [julia]
89
95
  entry: tools/formatter.jl
@@ -119,8 +125,8 @@ repos:
119
125
  # All comment are preserved
120
126
  - id: black
121
127
  name: black
122
- description: "Long strings are automatically folded into multilines by ruamel-yaml
123
- library!"
128
+ description: "Length of strings is automatically adjusted based on the value
129
+ of --line-width"
124
130
  entry: black
125
131
  language: python
126
132
  minimum_pre_commit_version: 2.9.2
@@ -134,7 +140,7 @@ repos:
134
140
 
135
141
  - id: julia-format
136
142
  name: format julia code
137
- description: Run `JuliaFormatter.jl` against Julia source files
143
+ description: Unicodeテキストは保持されます。
138
144
  language: julia
139
145
  types: [julia]
140
146
  entry: tools/formatter.jl
@@ -152,14 +158,25 @@ repos:
152
158
  additional_dependencies: ["cli:mdbook-lint:0.14.2"]
153
159
  ```
154
160
 
161
+ ## Supported Languages
162
+
163
+ Following local hook languages are currently supported:
164
+
165
+ - Go (golang)
166
+ - Julia
167
+ - Node.js (node)
168
+ - Python
169
+ - Rust
170
+
155
171
  ## Formatting
156
172
 
157
- A considerable amount of effort has been put into making `pre-commit-localupdate` respect the original style and preserve the comments in the pre-commit configuration files. Although it is currently folding long strings (for example, in description lines) and enforcing block indentation for better readability.
173
+ Significant effort has been made to ensure `pre-commit-localupdate` maintains the original style and preserves comments in pre-commit configuration files. However, since the current version of the underlying library does not perfectly preserve the original YAML file format after processing, `pre-commit-localupdate` automatically folds long string values (like descriptions) and enforces block indentation by default when updating files to enhance readability. Both behaviors can be adjusted using command-line parameters.
158
174
 
159
175
  ## Requirements
160
176
 
161
- - ruamel.yaml
162
- - requests
177
+ - `packaging`
178
+ - `requests`
179
+ - `ruamel.yaml`
163
180
 
164
181
  ## License
165
182
 
@@ -1,6 +1,6 @@
1
1
  # pre-commit-localupdate
2
2
 
3
- A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, Rust, Go, and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
3
+ A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,22 +16,27 @@ To check and update the `additional_dependencies` in your `.pre-commit-config.ya
16
16
  pre-commit-localupdate
17
17
  ```
18
18
 
19
- By default, the tool looks for `.pre-commit-config.yaml` in the current directory. To specify a custom file path, use the `-c` or `--config` argument:
20
-
21
- ```shell
22
- pre-commit-localupdate --config path/to/.pre-commit-config.yaml
23
- ```
24
-
25
- To check the dependencies without updating, use the `--dry-run` flag. The command will exit with a non-zero status code if any package needs updating:
26
-
27
- ```shell
28
- pre-commit-localupdate --dry-run
29
- ```
30
-
31
- To get debug output use `--debug` flag:
32
-
33
- ```shell
34
- pre-commit-localupdate --debug
19
+ All options:
20
+
21
+ ```text
22
+ usage: pre-commit-localupdate [-h] [--debug] [--dry-run] [-c PRE-COMMIT-CONFIG] [--timeout TIMEOUT]
23
+ [--indent-mapping INDENT_MAPPING] [--indent-sequence INDENT_SEQUENCE]
24
+ [--indent-offset INDENT_OFFSET] [--line-width LINE_WIDTH] [--version]
25
+
26
+ Automatically update additional dependencies within local hooks in a pre-commit config file.
27
+
28
+ options:
29
+ -h, --help show this help message and exit
30
+ --debug enable debug logging (default: False)
31
+ --dry-run dry run mode. Do not update the file and exit with a non-zero code if the
32
+ configuration file require an update. (default: False)
33
+ -c, --config PRE-COMMIT-CONFIG pre-commit config file path (default: .pre-commit-config.yaml)
34
+ --timeout TIMEOUT connection timeout in seconds (default: 10)
35
+ --indent-mapping INDENT_MAPPING YAML indentation for mappings (default: 2)
36
+ --indent-sequence INDENT_SEQUENCE YAML indentation for sequences (default: 4)
37
+ --indent-offset INDENT_OFFSET YAML indentation offset (default: 2)
38
+ --line-width LINE_WIDTH maximum line width (default: 80)
39
+ --version show program's version number and exit
35
40
  ```
36
41
 
37
42
  ## Example
@@ -54,7 +59,7 @@ repos:
54
59
  # All comment are preserved
55
60
  - id: black
56
61
  name: black
57
- description: "Long strings are automatically folded into multilines by ruamel-yaml library!"
62
+ description: "Length of strings is automatically adjusted based on the value of --line-width"
58
63
  entry: black
59
64
  language: python
60
65
  minimum_pre_commit_version: 2.9.2
@@ -68,7 +73,7 @@ repos:
68
73
 
69
74
  - id: julia-format
70
75
  name: format julia code
71
- description: Run `JuliaFormatter.jl` against Julia source files
76
+ description: Unicodeテキストは保持されます。
72
77
  language: julia
73
78
  types: [julia]
74
79
  entry: tools/formatter.jl
@@ -104,8 +109,8 @@ repos:
104
109
  # All comment are preserved
105
110
  - id: black
106
111
  name: black
107
- description: "Long strings are automatically folded into multilines by ruamel-yaml
108
- library!"
112
+ description: "Length of strings is automatically adjusted based on the value
113
+ of --line-width"
109
114
  entry: black
110
115
  language: python
111
116
  minimum_pre_commit_version: 2.9.2
@@ -119,7 +124,7 @@ repos:
119
124
 
120
125
  - id: julia-format
121
126
  name: format julia code
122
- description: Run `JuliaFormatter.jl` against Julia source files
127
+ description: Unicodeテキストは保持されます。
123
128
  language: julia
124
129
  types: [julia]
125
130
  entry: tools/formatter.jl
@@ -137,14 +142,25 @@ repos:
137
142
  additional_dependencies: ["cli:mdbook-lint:0.14.2"]
138
143
  ```
139
144
 
145
+ ## Supported Languages
146
+
147
+ Following local hook languages are currently supported:
148
+
149
+ - Go (golang)
150
+ - Julia
151
+ - Node.js (node)
152
+ - Python
153
+ - Rust
154
+
140
155
  ## Formatting
141
156
 
142
- A considerable amount of effort has been put into making `pre-commit-localupdate` respect the original style and preserve the comments in the pre-commit configuration files. Although it is currently folding long strings (for example, in description lines) and enforcing block indentation for better readability.
157
+ Significant effort has been made to ensure `pre-commit-localupdate` maintains the original style and preserves comments in pre-commit configuration files. However, since the current version of the underlying library does not perfectly preserve the original YAML file format after processing, `pre-commit-localupdate` automatically folds long string values (like descriptions) and enforces block indentation by default when updating files to enhance readability. Both behaviors can be adjusted using command-line parameters.
143
158
 
144
159
  ## Requirements
145
160
 
146
- - ruamel.yaml
147
- - requests
161
+ - `packaging`
162
+ - `requests`
163
+ - `ruamel.yaml`
148
164
 
149
165
  ## License
150
166
 
@@ -0,0 +1 @@
1
+ __version__ = '0.5.0'
@@ -11,10 +11,10 @@ to their latest versions.
11
11
 
12
12
  import logging
13
13
  import sys
14
- from pathlib import Path
15
14
 
16
15
  from pre_commit_localupdate.cli import parse_args
17
16
  from pre_commit_localupdate.error import PreCommitLocalUpdateError
17
+ from pre_commit_localupdate.io import YAMLFormat
18
18
  from pre_commit_localupdate.logs import setup_logging
19
19
  from pre_commit_localupdate.pre_commit_config import update_additional_dependencies
20
20
 
@@ -23,10 +23,18 @@ def main() -> None:
23
23
  """Main entry point for the script."""
24
24
  args = parse_args()
25
25
  setup_logging(debug=args.debug)
26
-
26
+ yaml_format = YAMLFormat(
27
+ indent_mapping=args.indent_mapping,
28
+ indent_sequence=args.indent_sequence,
29
+ indent_offset=args.indent_offset,
30
+ line_width=args.line_width,
31
+ )
27
32
  try:
28
- if update_additional_dependencies(Path(args.config), dry_run=args.dry_run):
33
+ if update_additional_dependencies(
34
+ args.config, args.timeout, yaml_format, dry_run=args.dry_run
35
+ ):
29
36
  if args.dry_run:
37
+ logging.info("Additional dependencies require updating!")
30
38
  sys.exit(1)
31
39
  logging.info("Done.")
32
40
  else:
@@ -0,0 +1,75 @@
1
+ # SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
2
+ # SPDX-License-Identifier: LGPL-3.0-or-later
3
+
4
+ import argparse
5
+ from pathlib import Path
6
+
7
+ from pre_commit_localupdate import __version__
8
+
9
+
10
+ def parse_args() -> argparse.Namespace:
11
+ """Parse command line arguments.
12
+
13
+ Returns:
14
+ argparse.Namespace: Parsed arguments.
15
+ """
16
+ parser = argparse.ArgumentParser(
17
+ description="Automatically update additional dependencies within local hooks in a pre-commit config file.",
18
+ formatter_class=lambda prog: argparse.ArgumentDefaultsHelpFormatter(
19
+ prog, max_help_position=40, width=120
20
+ ),
21
+ )
22
+ parser.add_argument(
23
+ "--debug",
24
+ action="store_true",
25
+ help="enable debug logging",
26
+ )
27
+ parser.add_argument(
28
+ "--dry-run",
29
+ action="store_true",
30
+ help="dry run mode. Do not update the file and exit with a non-zero code if the configuration file require an update.",
31
+ )
32
+ parser.add_argument(
33
+ "-c",
34
+ "--config",
35
+ type=Path,
36
+ help="pre-commit config file path",
37
+ default=".pre-commit-config.yaml",
38
+ metavar="PRE-COMMIT-CONFIG",
39
+ )
40
+ parser.add_argument(
41
+ "--timeout",
42
+ type=int,
43
+ help="connection timeout in seconds",
44
+ default=10,
45
+ )
46
+ parser.add_argument(
47
+ "--indent-mapping",
48
+ type=int,
49
+ help="YAML indentation for mappings",
50
+ default=2,
51
+ )
52
+ parser.add_argument(
53
+ "--indent-sequence",
54
+ type=int,
55
+ help="YAML indentation for sequences",
56
+ default=4,
57
+ )
58
+ parser.add_argument(
59
+ "--indent-offset",
60
+ type=int,
61
+ help="YAML indentation offset",
62
+ default=2,
63
+ )
64
+ parser.add_argument(
65
+ "--line-width",
66
+ type=int,
67
+ help="maximum line width",
68
+ default=80,
69
+ )
70
+ parser.add_argument(
71
+ "--version",
72
+ action="version",
73
+ version=f"pre-commit-localupdate {__version__}",
74
+ )
75
+ return parser.parse_args()
@@ -0,0 +1,121 @@
1
+ # SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
2
+ # SPDX-License-Identifier: LGPL-3.0-or-later
3
+
4
+ import io
5
+ import logging
6
+ import os
7
+ import tempfile
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+
11
+ from ruamel.yaml import YAML
12
+ from ruamel.yaml.comments import CommentedMap
13
+
14
+ from pre_commit_localupdate.error import PreCommitLocalUpdateError
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class YAMLFormat:
19
+ """Configuration for YAML file formatting parameters.
20
+
21
+ Attributes:
22
+ indent_mapping (int): YAML indentation for mappings
23
+ indent_sequence (int): YAML indentation for sequences
24
+ indent_offset (int): YAML indentation offset
25
+ line_width (int): maximum line width
26
+
27
+ """
28
+
29
+ indent_mapping: int
30
+ indent_sequence: int
31
+ indent_offset: int
32
+ line_width: int
33
+
34
+
35
+ def load_config_file(file_path: Path) -> tuple[list[str], str]:
36
+ """Reads pre-commit configuration file and returns its header lines and content.
37
+
38
+ Args:
39
+ file_path (Path): Path to config file
40
+
41
+ Returns:
42
+ tuple[list[str], str]: Header lines, config file content
43
+
44
+ Raises:
45
+ PreCommitLocalUpdateError: Error in reading config file
46
+ """
47
+ logging.debug("Reading configuration file: %s", file_path)
48
+
49
+ try:
50
+ file_content = file_path.read_text(encoding="utf-8")
51
+ except FileNotFoundError as exc:
52
+ raise PreCommitLocalUpdateError(f"File not found: {file_path}") from exc
53
+ except OSError as exc:
54
+ raise PreCommitLocalUpdateError(
55
+ f"IOError while reading file {file_path}"
56
+ ) from exc
57
+
58
+ raw_lines = file_content.splitlines(keepends=True)
59
+
60
+ content_start_index = 0
61
+ for i, line in enumerate(raw_lines):
62
+ stripped = line.strip()
63
+ if stripped == "---":
64
+ logging.debug("YAML marker found.")
65
+ content_start_index = i + 1
66
+ break
67
+ if stripped and not stripped.startswith("#"):
68
+ content_start_index = i
69
+ break
70
+
71
+ header_lines = raw_lines[:content_start_index]
72
+ content = "".join(raw_lines[content_start_index:])
73
+
74
+ return header_lines, content
75
+
76
+
77
+ def save_config_file(
78
+ file_path: Path,
79
+ config: CommentedMap,
80
+ header_lines: list[str],
81
+ yaml_dumper: YAML,
82
+ ) -> None:
83
+ """Writes pre-commit configuration file.
84
+
85
+ Args:
86
+ file_path (Path): Path to config file
87
+ config (CommentedMap): Config file content
88
+ header_lines (list[str]): File header lines
89
+ yaml_dumper (YAML): YAML dumper
90
+
91
+ Raises:
92
+ PreCommitLocalUpdateError: Error in writing config file
93
+ """
94
+
95
+ logging.debug("Writing modifications to disk...")
96
+ stream = io.StringIO()
97
+ yaml_dumper.dump(config, stream)
98
+ modified_body = stream.getvalue()
99
+ final_content = "".join(header_lines) + modified_body
100
+
101
+ temp_file_path = None
102
+ try:
103
+ with tempfile.NamedTemporaryFile(
104
+ mode="w",
105
+ encoding="utf-8",
106
+ dir=file_path.parent,
107
+ delete=False,
108
+ ) as temp_file:
109
+ temp_file.write(final_content)
110
+ os.fsync(temp_file.fileno())
111
+ temp_file_path = temp_file.name
112
+
113
+ os.replace(temp_file_path, file_path)
114
+ logging.info("Successfully updated %s", file_path)
115
+
116
+ except OSError as exc:
117
+ if temp_file_path and os.path.exists(temp_file_path):
118
+ os.unlink(temp_file_path)
119
+ raise PreCommitLocalUpdateError(
120
+ f"IOError while writing to file {file_path}"
121
+ ) from exc
@@ -6,7 +6,11 @@ import sys
6
6
 
7
7
 
8
8
  def setup_logging(*, debug: bool = False) -> None:
9
- """Configure logging based on the debug flag."""
9
+ """Configure logging based on the debug flag.
10
+
11
+ Args:
12
+ debug (bool): activate debug logs
13
+ """
10
14
  level = logging.DEBUG if debug else logging.INFO
11
15
  logging.basicConfig(
12
16
  level=level,
@@ -11,50 +11,40 @@ from .package import PackageBase
11
11
  # Go Proxy API endpoints
12
12
  GO_PKG_LATEST_VERSION_API_URL = "https://proxy.golang.org/{package_path}/@latest"
13
13
 
14
- REQUEST_TIMEOUT = 10
15
-
16
14
 
17
15
  class GoPackage(PackageBase):
18
16
  """Represents a Go module."""
19
17
 
20
18
  @classmethod
21
- def from_specification(package, spec: str) -> "GoPackage" | None:
19
+ def from_specification(cls, spec: str) -> "GoPackage" | None:
22
20
  """Parse a Go module specification string into a Package object.
23
21
 
24
- Handles formats like:
25
- - 'mvdan.cc/sh' (Module path only)
26
- - 'mvdan.cc/sh@v1.3.0' (Module path with specific version)
27
- - 'mvdan.cc/sh/v3' (Module path with major version suffix)
28
- - 'mvdan.cc/sh/v3@v3.10.0' (Major suffix with version)
29
- - 'mvdan.cc/sh/v3/cmd/shfmt' (Submodule)
30
- - 'mvdan.cc/sh/v3/cmd/shfmt@v3.10.0' (Submodule with version)
22
+ Supported formats:
23
+ - `mvdan.cc/sh` (Module path only)
24
+ - `mvdan.cc/sh@v1.3.0` (Module path with specific version)
25
+ - `mvdan.cc/sh/v3` (Module path with major version suffix)
26
+ - `mvdan.cc/sh/v3@v3.10.0` (Major suffix with version)
27
+ - `mvdan.cc/sh/v3/cmd/shfmt` (Submodule)
28
+ - `mvdan.cc/sh/v3/cmd/shfmt@v3.10.0` (Submodule with version)
31
29
 
32
30
  Args:
33
- package: The package specification string.
31
+ spec (str): The package specification string (without quotations).
34
32
 
35
33
  Returns:
36
- A Package instance if parsing succeeds, otherwise None.
34
+ "GoPackage" | None: A Package instance if parsing succeeds, otherwise None.
37
35
  """
38
- clean_spec = spec.strip().strip('"').strip("'")
39
36
 
40
- match = re.match(r"^([a-zA-Z0-9._/-]+)(@.+)?$", clean_spec)
37
+ match = re.match(r"^([a-zA-Z0-9._/-]+)(@.+)?$", spec)
41
38
 
42
39
  if not match:
43
- logging.warning(
44
- "Could not parse the Go package specification: %s", clean_spec
45
- )
46
40
  return None
47
41
 
48
42
  name = match.group(1)
49
43
  raw_spec = match.group(2)
50
44
 
51
- module_path = package._resolve_module_path(name)
52
- latest_version = package._fetch_latest_version(module_path)
53
-
54
- return package(
45
+ return cls(
55
46
  name=name,
56
47
  raw_spec=raw_spec,
57
- latest_version=latest_version,
58
48
  )
59
49
 
60
50
  @staticmethod
@@ -66,10 +56,10 @@ class GoPackage(PackageBase):
66
56
  additional path segments, it trims the path at the suffix.
67
57
 
68
58
  Args:
69
- package_path: The full submodule path.
59
+ package_path (str): The full submodule path.
70
60
 
71
61
  Returns:
72
- The resolved module path.
62
+ str: The resolved module path.
73
63
  """
74
64
 
75
65
  match = re.search(r"/v([2-9]|[1-9][0-9]+)(?=/)", package_path)
@@ -79,44 +69,38 @@ class GoPackage(PackageBase):
79
69
 
80
70
  return package_path
81
71
 
82
- @staticmethod
83
- def _fetch_latest_version(package_path: str) -> str | None:
72
+ def fetch_latest_version(self, connection_timeout: int) -> None:
84
73
  """Fetch the latest version of a Go module from proxy.golang.org.
85
74
 
86
75
  Args:
87
- package_path: The module path (e.g., mvdan.cc/sh/v3).
88
-
89
- Returns:
90
- The latest version string (e.g., v3.10.0) if found, otherwise None.
76
+ connection_timeout (int): Connection timeout in seconds.
91
77
  """
78
+ package_path = self._resolve_module_path(self.name)
92
79
  logging.debug("Fetching latest version for %s", package_path)
93
80
  try:
94
81
  url = GO_PKG_LATEST_VERSION_API_URL.format(package_path=package_path)
95
82
 
96
- response = requests.get(url, timeout=REQUEST_TIMEOUT)
83
+ response = requests.get(url, timeout=connection_timeout)
97
84
  response.raise_for_status()
98
85
 
99
86
  data = response.json()
100
- version = data.get("Version")
87
+ latest_version = data.get("Version")
101
88
 
102
- if isinstance(version, str):
103
- return version
89
+ if isinstance(latest_version, str):
90
+ self.latest_version = latest_version
104
91
 
105
- return None
106
92
  except requests.exceptions.RequestException as exc:
107
93
  logging.warning(
108
94
  "Could not fetch latest version for %s: %s", package_path, exc
109
95
  )
110
- return None
111
96
  except (KeyError, ValueError) as exc:
112
97
  logging.warning("Could not parse response for %s: %s", package_path, exc)
113
- return None
114
98
 
115
99
  def latest_version_specification(self) -> str | None:
116
100
  """Version specification of package pinned to the latest version.
117
101
 
118
102
  Returns:
119
- The latest version specification string if found, otherwise None.
103
+ str | None: The latest version specification string if found, otherwise None.
120
104
  """
121
105
  if not self.latest_version:
122
106
  return None