jaymd96-pants-baseline 0.1.7__py3-none-any.whl → 0.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: jaymd96-pants-baseline
3
- Version: 0.1.7
3
+ Version: 0.2.0
4
4
  Summary: Opinionated Python code quality baseline plugin for Pants build system
5
5
  Project-URL: Homepage, https://github.com/jaymd96/pants-baseline
6
6
  Project-URL: Repository, https://github.com/jaymd96/pants-baseline.git
@@ -21,6 +21,8 @@ Classifier: Programming Language :: Python :: 3.13
21
21
  Classifier: Topic :: Software Development :: Build Tools
22
22
  Classifier: Topic :: Software Development :: Quality Assurance
23
23
  Requires-Python: <4,>=3.11
24
+ Provides-Extra: claude
25
+ Requires-Dist: jaymd96-pants-claude-plugins>=0.2.0; extra == 'claude'
24
26
  Provides-Extra: dev
25
27
  Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
26
28
  Requires-Dist: pytest>=7.4.0; extra == 'dev'
@@ -54,7 +56,7 @@ backend_packages = [
54
56
  ]
55
57
 
56
58
  plugins = [
57
- "jaymd96-pants-baseline==0.1.0",
59
+ "jaymd96-pants-baseline==0.2.0",
58
60
  ]
59
61
  ```
60
62
 
@@ -308,7 +310,7 @@ backend_packages = [
308
310
  "pants.backend.python",
309
311
  "pants_baseline",
310
312
  ]
311
- plugins = ["jaymd96-pants-baseline==0.1.0"]
313
+ plugins = ["jaymd96-pants-baseline==0.2.0"]
312
314
 
313
315
  [python]
314
316
  interpreter_constraints = ["CPython>=3.13,<4"]
@@ -346,6 +348,37 @@ strict = true
346
348
  | MyPy/Pyright | ty |
347
349
  | pip-audit | uv audit |
348
350
 
351
+ ## Claude Code Integration
352
+
353
+ This plugin bundles recommended [Claude Code](https://claude.ai/code) plugins for enhanced AI-assisted development workflows.
354
+
355
+ ### Install Bundled Claude Plugins
356
+
357
+ When combined with [jaymd96-pants-claude-plugins](https://github.com/jaymd96/pants-claude-plugins):
358
+
359
+ ```toml
360
+ # pants.toml
361
+ [GLOBAL]
362
+ plugins = [
363
+ "jaymd96-pants-baseline==0.2.0",
364
+ "jaymd96-pants-claude-plugins>=0.2.0",
365
+ ]
366
+ backend_packages = [
367
+ "pants_baseline",
368
+ "pants_claude_plugins",
369
+ ]
370
+ ```
371
+
372
+ Then run:
373
+
374
+ ```bash
375
+ pants claude-install --include-bundled ::
376
+ ```
377
+
378
+ This automatically installs:
379
+ - **github** - GitHub integration for PR workflows and issue management
380
+ - **commit-commands** - Git workflow commands for commits, pushes, and PRs
381
+
349
382
  ## Development
350
383
 
351
384
  ### Setup
@@ -0,0 +1,26 @@
1
+ pants_baseline/__about__.py,sha256=wxKDEvde9_K-nhyadAqBTbIh_mR7ckFwDJRU14BkV8A,98
2
+ pants_baseline/__init__.py,sha256=uVRGi1D2gFjc7emmeewWdcvpO-NsUuKsMbX3rztOxWU,655
3
+ pants_baseline/bundled_claude_plugins.py,sha256=jfNzFrvZBvv8Iz1XMLomgIa993ZYH_DMNOk-apFs8-g,926
4
+ pants_baseline/register.py,sha256=gdODsaI7VIzU2tGONANsg9KbKZkHidmLs2AyvUNIypg,1675
5
+ pants_baseline/targets.py,sha256=Z9O09Aqd5inMqwIUFt4HSE9HtWjn8pGSU4FZHg22Tpo,3379
6
+ pants_baseline/goals/__init__.py,sha256=pf6KU2CIQuDkx8ER3IS0H-kuNbBtX-AH5B5SnSP9_yw,192
7
+ pants_baseline/goals/audit.py,sha256=i7zyyKssWw6EE2zN5putWP9sikkcjUKn7g3Jrapv994,2380
8
+ pants_baseline/goals/fmt.py,sha256=CyUPhy42rscUzJp4DhSRp3FGhGYcIKN42b46l1hJ9tY,2432
9
+ pants_baseline/goals/lint.py,sha256=vGyG-wvjgjE4dgglmTOiFNnng2bQbOQXkZ3Fd2HdiOU,2435
10
+ pants_baseline/goals/test.py,sha256=THW4kJAFbAzPCjLbq1dxg81T19QdywXYiwTNKSB4z8M,1653
11
+ pants_baseline/goals/typecheck.py,sha256=nqfwy1BZqhEzlDX-_hme9mKuDI2KqH-XpN4ygzWMQ6Y,2626
12
+ pants_baseline/rules/__init__.py,sha256=UpvDpGVImhRfp2_VeUNsRPGiWjBbMI6AV1-Yx3kS0Gg,252
13
+ pants_baseline/rules/audit_rules.py,sha256=gr-2u0u07z62Q42c9vXVGJng8UPIP5JzZ-SKrl9z7yM,2762
14
+ pants_baseline/rules/fmt_rules.py,sha256=O-JQVk565H8w6jlsG-cqndzNaig3alepqTV0zKhfyDw,4174
15
+ pants_baseline/rules/lint_rules.py,sha256=rYsbaPyYNDVDJn_dF91ews8iskcj2QoqnzZInLxkIzc,4219
16
+ pants_baseline/rules/test_rules.py,sha256=jj4lk3-mueOPujPFPK2TCdBFZZA_vovdDdHED9jGp7U,4225
17
+ pants_baseline/rules/typecheck_rules.py,sha256=XmL6uIXwjphB1YDVMrCM6A_Wa_1H-gHuLg8x59v_YQo,4499
18
+ pants_baseline/subsystems/__init__.py,sha256=LteH_qmUIgRAnXYmmi7f6o894QfpY3hMNH5dlvJbSoM,387
19
+ pants_baseline/subsystems/baseline.py,sha256=KWDRMdLOUN5cNHntY8f97bSsoITXwmX4ET6n2aW-cRk,2049
20
+ pants_baseline/subsystems/ruff.py,sha256=NW0AFv59-j6ANkZG8LjvuXPzWBD4yDsEr7Pb6eZbdck,3941
21
+ pants_baseline/subsystems/ty.py,sha256=OpaU8Z7Bk6kj5QAfhPom5L9v8sKNR8XF664_U5mUVJw,3419
22
+ pants_baseline/subsystems/uv.py,sha256=dXmVzg4ZxzHa4g_TowEZXMYuhKiTOHjqqadkNrZQ9jk,3066
23
+ jaymd96_pants_baseline-0.2.0.dist-info/METADATA,sha256=XsPPcHLtQ4TdFAAjbezNEDcPhcw_Hj7t68NiNwlfcIc,8764
24
+ jaymd96_pants_baseline-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
+ jaymd96_pants_baseline-0.2.0.dist-info/licenses/LICENSE,sha256=oLGLZv7XKM_oKCbdMW1bZB37SXsdexmhNSuh3Xg4m4I,10754
26
+ jaymd96_pants_baseline-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  """Version information for jaymd96-pants-baseline."""
2
2
 
3
- __version__ = "0.1.7"
3
+ __version__ = "0.2.0"
4
4
  __author__ = "James"
@@ -0,0 +1,29 @@
1
+ """Bundled Claude Code plugins for pants-baseline.
2
+
3
+ These plugins are automatically discovered and installed when users run:
4
+ pants claude-install --include-bundled ::
5
+
6
+ This requires the jaymd96-pants-claude-plugins package to be installed.
7
+ """
8
+
9
+ # Marketplaces to add before installing plugins
10
+ # The demo marketplace contains commit-commands and other workflow plugins
11
+ BUNDLED_MARKETPLACES = [
12
+ "anthropics/claude-code", # Demo plugins marketplace
13
+ ]
14
+
15
+ # Claude Code plugins to install
16
+ BUNDLED_CLAUDE_PLUGINS = [
17
+ {
18
+ "plugin": "github",
19
+ "marketplace": "claude-plugins-official",
20
+ "scope": "project",
21
+ "description": "GitHub integration for PR workflows and issue management",
22
+ },
23
+ {
24
+ "plugin": "commit-commands",
25
+ "marketplace": "anthropics-claude-code",
26
+ "scope": "project",
27
+ "description": "Git workflow commands for commits, pushes, and PRs",
28
+ },
29
+ ]
@@ -4,13 +4,16 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Iterable
6
6
 
7
+ from pants.core.goals.fmt import FmtResult
7
8
  from pants.engine.console import Console
8
9
  from pants.engine.goal import Goal, GoalSubsystem
9
- from pants.engine.rules import collect_rules, goal_rule
10
- from pants.engine.target import Targets
10
+ from pants.engine.rules import Get, collect_rules, goal_rule
11
+ from pants.engine.target import FilteredTargets
11
12
 
13
+ from pants_baseline.rules.fmt_rules import RuffFmtFieldSet, RuffFmtRequest
12
14
  from pants_baseline.subsystems.baseline import BaselineSubsystem
13
15
  from pants_baseline.subsystems.ruff import RuffSubsystem
16
+ from pants_baseline.targets import BaselineSourcesField
14
17
 
15
18
 
16
19
  class BaselineFmtSubsystem(GoalSubsystem):
@@ -30,7 +33,7 @@ class BaselineFmt(Goal):
30
33
  @goal_rule
31
34
  async def run_baseline_fmt(
32
35
  console: Console,
33
- targets: Targets,
36
+ targets: FilteredTargets,
34
37
  baseline_subsystem: BaselineSubsystem,
35
38
  ruff_subsystem: RuffSubsystem,
36
39
  ) -> BaselineFmt:
@@ -39,15 +42,37 @@ async def run_baseline_fmt(
39
42
  console.print_stdout("Python baseline is disabled.")
40
43
  return BaselineFmt(exit_code=0)
41
44
 
42
- console.print_stdout("Running Ruff formatter...")
43
- console.print_stdout(f" Target Python version: {baseline_subsystem.python_version}")
44
- console.print_stdout(f" Line length: {baseline_subsystem.line_length}")
45
- console.print_stdout(f" Quote style: {ruff_subsystem.quote_style}")
46
- console.print_stdout(f" Indent style: {ruff_subsystem.indent_style}")
47
- console.print_stdout("")
45
+ # Filter targets that have BaselineSourcesField
46
+ applicable_targets = [
47
+ t for t in targets
48
+ if t.has_field(BaselineSourcesField)
49
+ ]
48
50
 
49
- # The actual formatting is handled by the FmtTargetsRequest mechanism
50
- # This goal just provides a user-friendly entry point
51
+ if not applicable_targets:
52
+ console.print_stdout("No baseline_python_project targets found.")
53
+ return BaselineFmt(exit_code=0)
54
+
55
+ # Create field sets for each target
56
+ field_sets = [
57
+ RuffFmtFieldSet.create(t)
58
+ for t in applicable_targets
59
+ ]
60
+
61
+ # Create the fmt request and run it
62
+ request = RuffFmtRequest(field_sets)
63
+ result = await Get(FmtResult, RuffFmtRequest, request)
64
+
65
+ # Print results
66
+ if result.stdout:
67
+ console.print_stdout(result.stdout)
68
+ if result.stderr:
69
+ console.print_stderr(result.stderr)
70
+
71
+ files_changed = result.input != result.output
72
+ if files_changed:
73
+ console.print_stdout(f"✓ Formatted {len(field_sets)} target(s)")
74
+ else:
75
+ console.print_stdout(f"✓ {len(field_sets)} target(s) already formatted")
51
76
 
52
77
  return BaselineFmt(exit_code=0)
53
78
 
@@ -4,17 +4,16 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Iterable
6
6
 
7
- from pants.core.goals.lint import LintFilesRequest, LintResult
7
+ from pants.core.goals.lint import LintResult
8
8
  from pants.engine.console import Console
9
- from pants.engine.fs import PathGlobs, Paths
10
9
  from pants.engine.goal import Goal, GoalSubsystem
11
10
  from pants.engine.rules import Get, collect_rules, goal_rule
12
- from pants.engine.target import Targets
13
- from pants.util.logging import LogLevel
11
+ from pants.engine.target import FieldSet, FilteredTargets
14
12
 
15
- from pants_baseline.rules.lint_rules import RuffLintRequest
13
+ from pants_baseline.rules.lint_rules import RuffLintFieldSet, RuffLintRequest
16
14
  from pants_baseline.subsystems.baseline import BaselineSubsystem
17
15
  from pants_baseline.subsystems.ruff import RuffSubsystem
16
+ from pants_baseline.targets import BaselineSourcesField
18
17
 
19
18
 
20
19
  class BaselineLintSubsystem(GoalSubsystem):
@@ -34,7 +33,7 @@ class BaselineLint(Goal):
34
33
  @goal_rule
35
34
  async def run_baseline_lint(
36
35
  console: Console,
37
- targets: Targets,
36
+ targets: FilteredTargets,
38
37
  baseline_subsystem: BaselineSubsystem,
39
38
  ruff_subsystem: RuffSubsystem,
40
39
  ) -> BaselineLint:
@@ -43,16 +42,38 @@ async def run_baseline_lint(
43
42
  console.print_stdout("Python baseline is disabled.")
44
43
  return BaselineLint(exit_code=0)
45
44
 
46
- console.print_stdout("Running Ruff linter...")
47
- console.print_stdout(f" Target Python version: {baseline_subsystem.python_version}")
48
- console.print_stdout(f" Line length: {baseline_subsystem.line_length}")
49
- console.print_stdout(f" Rules: {', '.join(ruff_subsystem.select[:5])}...")
50
- console.print_stdout("")
45
+ # Filter targets that have BaselineSourcesField
46
+ applicable_targets = [
47
+ t for t in targets
48
+ if t.has_field(BaselineSourcesField)
49
+ ]
51
50
 
52
- # The actual linting is handled by the LintTargetsRequest mechanism
53
- # This goal just provides a user-friendly entry point
51
+ if not applicable_targets:
52
+ console.print_stdout("No baseline_python_project targets found.")
53
+ return BaselineLint(exit_code=0)
54
+
55
+ # Create field sets for each target
56
+ field_sets = [
57
+ RuffLintFieldSet.create(t)
58
+ for t in applicable_targets
59
+ ]
60
+
61
+ # Create the lint request and run it
62
+ request = RuffLintRequest(field_sets)
63
+ result = await Get(LintResult, RuffLintRequest, request)
64
+
65
+ # Print results
66
+ if result.stdout:
67
+ console.print_stdout(result.stdout)
68
+ if result.stderr:
69
+ console.print_stderr(result.stderr)
70
+
71
+ if result.exit_code == 0:
72
+ console.print_stdout(f"✓ Linted {len(field_sets)} target(s) successfully")
73
+ else:
74
+ console.print_stderr(f"✗ Linting failed with exit code {result.exit_code}")
54
75
 
55
- return BaselineLint(exit_code=0)
76
+ return BaselineLint(exit_code=result.exit_code)
56
77
 
57
78
 
58
79
  def rules() -> Iterable:
@@ -4,13 +4,16 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Iterable
6
6
 
7
+ from pants.core.goals.check import CheckResults
7
8
  from pants.engine.console import Console
8
9
  from pants.engine.goal import Goal, GoalSubsystem
9
- from pants.engine.rules import collect_rules, goal_rule
10
- from pants.engine.target import Targets
10
+ from pants.engine.rules import Get, collect_rules, goal_rule
11
+ from pants.engine.target import FilteredTargets
11
12
 
13
+ from pants_baseline.rules.typecheck_rules import TyCheckRequest, TyFieldSet
12
14
  from pants_baseline.subsystems.baseline import BaselineSubsystem
13
15
  from pants_baseline.subsystems.ty import TySubsystem
16
+ from pants_baseline.targets import BaselineSourcesField
14
17
 
15
18
 
16
19
  class BaselineTypecheckSubsystem(GoalSubsystem):
@@ -30,7 +33,7 @@ class BaselineTypecheck(Goal):
30
33
  @goal_rule
31
34
  async def run_baseline_typecheck(
32
35
  console: Console,
33
- targets: Targets,
36
+ targets: FilteredTargets,
34
37
  baseline_subsystem: BaselineSubsystem,
35
38
  ty_subsystem: TySubsystem,
36
39
  ) -> BaselineTypecheck:
@@ -39,16 +42,42 @@ async def run_baseline_typecheck(
39
42
  console.print_stdout("Python baseline is disabled.")
40
43
  return BaselineTypecheck(exit_code=0)
41
44
 
42
- console.print_stdout("Running ty type checker...")
43
- console.print_stdout(f" Target Python version: {baseline_subsystem.python_version}")
44
- console.print_stdout(f" Strict mode: {ty_subsystem.strict}")
45
- console.print_stdout(f" Output format: {ty_subsystem.output_format}")
46
- console.print_stdout("")
45
+ # Filter targets that have BaselineSourcesField
46
+ applicable_targets = [
47
+ t for t in targets
48
+ if t.has_field(BaselineSourcesField)
49
+ ]
47
50
 
48
- # The actual type checking is handled by the CheckRequest mechanism
49
- # This goal just provides a user-friendly entry point
51
+ if not applicable_targets:
52
+ console.print_stdout("No baseline_python_project targets found.")
53
+ return BaselineTypecheck(exit_code=0)
50
54
 
51
- return BaselineTypecheck(exit_code=0)
55
+ # Create field sets for each target
56
+ field_sets = [
57
+ TyFieldSet.create(t)
58
+ for t in applicable_targets
59
+ ]
60
+
61
+ # Create the check request and run it
62
+ request = TyCheckRequest(field_sets)
63
+ results = await Get(CheckResults, TyCheckRequest, request)
64
+
65
+ # Print results
66
+ exit_code = 0
67
+ for result in results.results:
68
+ if result.stdout:
69
+ console.print_stdout(result.stdout)
70
+ if result.stderr:
71
+ console.print_stderr(result.stderr)
72
+ if result.exit_code != 0:
73
+ exit_code = result.exit_code
74
+
75
+ if exit_code == 0:
76
+ console.print_stdout(f"✓ Type checked {len(field_sets)} target(s) successfully")
77
+ else:
78
+ console.print_stderr(f"✗ Type checking failed with exit code {exit_code}")
79
+
80
+ return BaselineTypecheck(exit_code=exit_code)
52
81
 
53
82
 
54
83
  def rules() -> Iterable:
@@ -6,7 +6,7 @@ It registers all rules, targets, and subsystems provided by this plugin.
6
6
 
7
7
  from typing import Iterable
8
8
 
9
- from pants.engine.rules import Rule, collect_rules
9
+ from pants.engine.rules import Rule
10
10
 
11
11
  from pants_baseline.goals import audit as audit_goal
12
12
  from pants_baseline.goals import fmt as fmt_goal
@@ -22,18 +22,23 @@ from pants_baseline.targets import BaselinePythonProject
22
22
 
23
23
 
24
24
  def rules() -> Iterable[Rule]:
25
- """Return all rules provided by this plugin."""
25
+ """Return all rules provided by this plugin.
26
+
27
+ Each module's rules() function returns both @rule decorated functions
28
+ AND UnionRule registrations. We must call the rules() functions directly
29
+ rather than using collect_rules() which only collects @rule functions.
30
+ """
26
31
  return [
27
- *collect_rules(lint_rules),
28
- *collect_rules(fmt_rules),
29
- *collect_rules(typecheck_rules),
30
- *collect_rules(test_rules),
31
- *collect_rules(audit_rules),
32
- *collect_rules(lint_goal),
33
- *collect_rules(fmt_goal),
34
- *collect_rules(typecheck_goal),
35
- *collect_rules(test_goal),
36
- *collect_rules(audit_goal),
32
+ *lint_rules.rules(),
33
+ *fmt_rules.rules(),
34
+ *typecheck_rules.rules(),
35
+ *test_rules.rules(),
36
+ *audit_rules.rules(),
37
+ *lint_goal.rules(),
38
+ *fmt_goal.rules(),
39
+ *typecheck_goal.rules(),
40
+ *test_goal.rules(),
41
+ *audit_goal.rules(),
37
42
  ]
38
43
 
39
44
 
@@ -3,10 +3,15 @@
3
3
  from dataclasses import dataclass
4
4
  from typing import Iterable
5
5
 
6
+ from pants.core.util_rules.external_tool import DownloadedExternalTool, ExternalToolRequest
7
+ from pants.engine.fs import Digest, MergeDigests, PathGlobs, Snapshot
8
+ from pants.engine.platform import Platform
6
9
  from pants.engine.process import FallibleProcessResult, Process
7
10
  from pants.engine.rules import Get, collect_rules, rule
8
11
  from pants.util.logging import LogLevel
9
12
 
13
+ from pants_baseline.subsystems.uv import UvSubsystem
14
+
10
15
 
11
16
  @dataclass(frozen=True)
12
17
  class AuditResult:
@@ -30,22 +35,45 @@ class UvAuditRequest:
30
35
  @rule(desc="Audit dependencies with uv", level=LogLevel.DEBUG)
31
36
  async def run_uv_audit(
32
37
  request: UvAuditRequest,
38
+ uv_subsystem: UvSubsystem,
39
+ platform: Platform,
33
40
  ) -> AuditResult:
34
41
  """Run uv audit on dependencies."""
42
+ # Download uv
43
+ downloaded_uv = await Get(
44
+ DownloadedExternalTool,
45
+ ExternalToolRequest,
46
+ uv_subsystem.get_request(platform),
47
+ )
48
+
49
+ # Get the lock file if it exists
50
+ lock_file_snapshot = await Get(
51
+ Snapshot,
52
+ PathGlobs([request.lock_file, "pyproject.toml", "requirements.txt"]),
53
+ )
54
+
55
+ # Merge the uv binary with lock files
56
+ input_digest = await Get(
57
+ Digest,
58
+ MergeDigests([downloaded_uv.digest, lock_file_snapshot.digest]),
59
+ )
60
+
35
61
  # Build ignore args
36
62
  ignore_args = []
37
63
  for vuln in request.ignore_vulns:
38
64
  ignore_args.extend(["--ignore", vuln])
39
65
 
40
66
  argv = [
41
- "uv",
67
+ downloaded_uv.exe,
68
+ "pip",
42
69
  "audit",
43
70
  f"--output-format={request.output_format}",
44
71
  *ignore_args,
45
72
  ]
46
73
 
47
- process: Process = Process(
74
+ process = Process(
48
75
  argv=argv,
76
+ input_digest=input_digest,
49
77
  description="Run uv security audit",
50
78
  level=LogLevel.DEBUG,
51
79
  )
@@ -3,13 +3,14 @@
3
3
  from dataclasses import dataclass
4
4
  from typing import Iterable
5
5
 
6
- from pants.core.goals.fmt import FmtResult, FmtTargetsRequest
6
+ from pants.core.goals.fmt import FmtResult, FmtTargetsRequest, PartitionerType
7
+ from pants.core.util_rules.external_tool import DownloadedExternalTool, ExternalToolRequest
7
8
  from pants.core.util_rules.source_files import SourceFiles, SourceFilesRequest
8
- from pants.engine.fs import Digest, Snapshot
9
+ from pants.engine.fs import Digest, MergeDigests, Snapshot
10
+ from pants.engine.platform import Platform
9
11
  from pants.engine.process import FallibleProcessResult, Process
10
- from pants.engine.rules import Get, collect_rules, rule
11
- from pants.engine.target import FieldSet
12
- from pants.engine.unions import UnionRule
12
+ from pants.engine.rules import Get, MultiGet, collect_rules, rule
13
+ from pants.engine.target import FieldSet, Target
13
14
  from pants.util.logging import LogLevel
14
15
 
15
16
  from pants_baseline.subsystems.baseline import BaselineSubsystem
@@ -26,72 +27,90 @@ class RuffFmtFieldSet(FieldSet):
26
27
  sources: BaselineSourcesField
27
28
  skip_fmt: SkipFormatField
28
29
 
30
+ @classmethod
31
+ def opt_out(cls, tgt: Target) -> bool:
32
+ """Allow targets to opt out of formatting."""
33
+ return tgt.get(SkipFormatField).value
34
+
29
35
 
30
36
  class RuffFmtRequest(FmtTargetsRequest):
31
37
  """Request to run Ruff formatting."""
32
38
 
33
39
  field_set_type = RuffFmtFieldSet
34
- tool_name = "ruff"
40
+ tool_subsystem = RuffSubsystem
41
+ partitioner_type = PartitionerType.DEFAULT_SINGLE_PARTITION
35
42
 
36
43
 
37
44
  @rule(desc="Format with Ruff", level=LogLevel.DEBUG)
38
45
  async def run_ruff_fmt(
39
- request: RuffFmtRequest,
46
+ request: RuffFmtRequest.Batch,
40
47
  ruff_subsystem: RuffSubsystem,
41
48
  baseline_subsystem: BaselineSubsystem,
49
+ platform: Platform,
42
50
  ) -> FmtResult:
43
51
  """Run Ruff formatter on Python files."""
52
+ field_sets = request.elements
53
+ snapshot = request.snapshot
54
+
44
55
  if not baseline_subsystem.enabled:
45
56
  return FmtResult(
46
- input=request.snapshot,
47
- output=request.snapshot,
57
+ input=snapshot,
58
+ output=snapshot,
48
59
  stdout="",
49
60
  stderr="",
50
61
  formatter_name="ruff",
51
62
  )
52
63
 
53
- # Filter out skipped targets
54
- field_sets = [fs for fs in request.field_sets if not fs.skip_fmt.value]
55
-
56
64
  if not field_sets:
57
65
  return FmtResult(
58
- input=request.snapshot,
59
- output=request.snapshot,
66
+ input=snapshot,
67
+ output=snapshot,
60
68
  stdout="No targets to format",
61
69
  stderr="",
62
70
  formatter_name="ruff",
63
71
  )
64
72
 
65
- # Get source files
66
- source_files_request: SourceFilesRequest = SourceFilesRequest(
67
- sources_fields=[fs.sources for fs in field_sets],
68
- for_sources_types=(BaselineSourcesField,),
73
+ # Download ruff and get source files in parallel
74
+ downloaded_ruff, sources = await MultiGet(
75
+ Get(DownloadedExternalTool, ExternalToolRequest, ruff_subsystem.get_request(platform)),
76
+ Get(
77
+ SourceFiles,
78
+ SourceFilesRequest(
79
+ sources_fields=[fs.sources for fs in field_sets],
80
+ for_sources_types=(BaselineSourcesField,),
81
+ ),
82
+ ),
69
83
  )
70
- sources = await Get(SourceFiles, SourceFilesRequest, source_files_request)
71
84
 
72
85
  if not sources.files:
73
86
  return FmtResult(
74
- input=request.snapshot,
75
- output=request.snapshot,
87
+ input=snapshot,
88
+ output=snapshot,
76
89
  stdout="No files to format",
77
90
  stderr="",
78
91
  formatter_name="ruff",
79
92
  )
80
93
 
94
+ # Merge the ruff binary with the source files
95
+ input_digest = await Get(
96
+ Digest,
97
+ MergeDigests([downloaded_ruff.digest, sources.snapshot.digest]),
98
+ )
99
+
81
100
  # Build Ruff format command
82
101
  argv = [
83
- "ruff",
102
+ downloaded_ruff.exe,
84
103
  "format",
85
- f"--target-version={baseline_subsystem.get_python_target_version()}",
104
+ f"--target-version=py{baseline_subsystem.python_version.replace('.', '')}",
86
105
  f"--line-length={baseline_subsystem.line_length}",
87
106
  f"--quote-style={ruff_subsystem.quote_style}",
88
107
  f"--indent-style={ruff_subsystem.indent_style}",
89
108
  *sources.files,
90
109
  ]
91
110
 
92
- process: Process = Process(
111
+ process = Process(
93
112
  argv=argv,
94
- input_digest=sources.snapshot.digest,
113
+ input_digest=input_digest,
95
114
  output_files=sources.files,
96
115
  description=f"Run Ruff format on {len(sources.files)} files",
97
116
  level=LogLevel.DEBUG,
@@ -115,5 +134,5 @@ def rules() -> Iterable:
115
134
  """Return all format rules."""
116
135
  return [
117
136
  *collect_rules(),
118
- UnionRule(FmtTargetsRequest, RuffFmtRequest),
137
+ *RuffFmtRequest.rules(),
119
138
  ]
@@ -3,15 +3,15 @@
3
3
  from dataclasses import dataclass
4
4
  from typing import Iterable
5
5
 
6
- from pants.core.goals.lint import LintResult, LintTargetsRequest
6
+ from pants.core.goals.lint import LintResult, LintTargetsRequest, PartitionerType
7
7
  from pants.core.util_rules.external_tool import DownloadedExternalTool, ExternalToolRequest
8
+ from pants.core.util_rules.partitions import Partitions
8
9
  from pants.core.util_rules.source_files import SourceFiles, SourceFilesRequest
9
10
  from pants.engine.fs import Digest, MergeDigests
10
11
  from pants.engine.platform import Platform
11
12
  from pants.engine.process import FallibleProcessResult, Process
12
13
  from pants.engine.rules import Get, MultiGet, collect_rules, rule
13
14
  from pants.engine.target import FieldSet, Target
14
- from pants.engine.unions import UnionRule
15
15
  from pants.util.logging import LogLevel
16
16
 
17
17
  from pants_baseline.subsystems.baseline import BaselineSubsystem
@@ -28,26 +28,23 @@ class RuffLintFieldSet(FieldSet):
28
28
  sources: BaselineSourcesField
29
29
  skip_lint: SkipLintField
30
30
 
31
+ @classmethod
32
+ def opt_out(cls, tgt: Target) -> bool:
33
+ """Allow targets to opt out of linting."""
34
+ return tgt.get(SkipLintField).value
35
+
31
36
 
32
37
  class RuffLintRequest(LintTargetsRequest):
33
38
  """Request to run Ruff linting."""
34
39
 
35
40
  field_set_type = RuffLintFieldSet
36
- tool_name = "ruff"
37
-
38
-
39
- @dataclass(frozen=True)
40
- class RuffLintResult:
41
- """Result of running Ruff lint."""
42
-
43
- exit_code: int
44
- stdout: str
45
- stderr: str
41
+ tool_subsystem = RuffSubsystem
42
+ partitioner_type = PartitionerType.DEFAULT_SINGLE_PARTITION
46
43
 
47
44
 
48
45
  @rule(desc="Lint with Ruff", level=LogLevel.DEBUG)
49
46
  async def run_ruff_lint(
50
- request: RuffLintRequest,
47
+ request: RuffLintRequest.Batch,
51
48
  ruff_subsystem: RuffSubsystem,
52
49
  baseline_subsystem: BaselineSubsystem,
53
50
  platform: Platform,
@@ -62,8 +59,7 @@ async def run_ruff_lint(
62
59
  partition_description=None,
63
60
  )
64
61
 
65
- # Filter out skipped targets
66
- field_sets = [fs for fs in request.field_sets if not fs.skip_lint.value]
62
+ field_sets = request.elements
67
63
 
68
64
  if not field_sets:
69
65
  return LintResult(
@@ -74,12 +70,17 @@ async def run_ruff_lint(
74
70
  partition_description=None,
75
71
  )
76
72
 
77
- # Get source files
78
- source_files_request: SourceFilesRequest = SourceFilesRequest(
79
- sources_fields=[fs.sources for fs in field_sets],
80
- for_sources_types=(BaselineSourcesField,),
73
+ # Download ruff and get source files in parallel
74
+ downloaded_ruff, sources = await MultiGet(
75
+ Get(DownloadedExternalTool, ExternalToolRequest, ruff_subsystem.get_request(platform)),
76
+ Get(
77
+ SourceFiles,
78
+ SourceFilesRequest(
79
+ sources_fields=[fs.sources for fs in field_sets],
80
+ for_sources_types=(BaselineSourcesField,),
81
+ ),
82
+ ),
81
83
  )
82
- sources = await Get(SourceFiles, SourceFilesRequest, source_files_request)
83
84
 
84
85
  if not sources.files:
85
86
  return LintResult(
@@ -90,14 +91,20 @@ async def run_ruff_lint(
90
91
  partition_description=None,
91
92
  )
92
93
 
94
+ # Merge the ruff binary with the source files
95
+ input_digest = await Get(
96
+ Digest,
97
+ MergeDigests([downloaded_ruff.digest, sources.snapshot.digest]),
98
+ )
99
+
93
100
  # Build Ruff command
94
101
  select_args = [f"--select={','.join(ruff_subsystem.select)}"] if ruff_subsystem.select else []
95
102
  ignore_args = [f"--ignore={','.join(ruff_subsystem.ignore)}"] if ruff_subsystem.ignore else []
96
103
 
97
104
  argv = [
98
- "ruff",
105
+ downloaded_ruff.exe,
99
106
  "check",
100
- f"--target-version={baseline_subsystem.get_python_target_version()}",
107
+ f"--target-version=py{baseline_subsystem.python_version.replace('.', '')}",
101
108
  f"--line-length={baseline_subsystem.line_length}",
102
109
  *select_args,
103
110
  *ignore_args,
@@ -105,9 +112,9 @@ async def run_ruff_lint(
105
112
  *sources.files,
106
113
  ]
107
114
 
108
- process: Process = Process(
115
+ process = Process(
109
116
  argv=argv,
110
- input_digest=sources.snapshot.digest,
117
+ input_digest=input_digest,
111
118
  description=f"Run Ruff lint on {len(sources.files)} files",
112
119
  level=LogLevel.DEBUG,
113
120
  )
@@ -119,7 +126,7 @@ async def run_ruff_lint(
119
126
  stdout=result.stdout.decode(),
120
127
  stderr=result.stderr.decode(),
121
128
  linter_name="ruff",
122
- partition_description=None,
129
+ partition_description=request.partition_metadata,
123
130
  )
124
131
 
125
132
 
@@ -127,5 +134,5 @@ def rules() -> Iterable:
127
134
  """Return all lint rules."""
128
135
  return [
129
136
  *collect_rules(),
130
- UnionRule(LintTargetsRequest, RuffLintRequest),
137
+ *RuffLintRequest.rules(),
131
138
  ]
@@ -4,10 +4,13 @@ from dataclasses import dataclass
4
4
  from typing import Iterable
5
5
 
6
6
  from pants.core.goals.check import CheckRequest, CheckResult, CheckResults
7
+ from pants.core.util_rules.external_tool import DownloadedExternalTool, ExternalToolRequest
7
8
  from pants.core.util_rules.source_files import SourceFiles, SourceFilesRequest
9
+ from pants.engine.fs import Digest, MergeDigests
10
+ from pants.engine.platform import Platform
8
11
  from pants.engine.process import FallibleProcessResult, Process
9
- from pants.engine.rules import Get, collect_rules, rule
10
- from pants.engine.target import FieldSet
12
+ from pants.engine.rules import Get, MultiGet, collect_rules, rule
13
+ from pants.engine.target import FieldSet, Target
11
14
  from pants.engine.unions import UnionRule
12
15
  from pants.util.logging import LogLevel
13
16
 
@@ -25,6 +28,11 @@ class TyFieldSet(FieldSet):
25
28
  sources: BaselineSourcesField
26
29
  skip_typecheck: SkipTypecheckField
27
30
 
31
+ @classmethod
32
+ def opt_out(cls, tgt: Target) -> bool:
33
+ """Allow targets to opt out of type checking."""
34
+ return tgt.get(SkipTypecheckField).value
35
+
28
36
 
29
37
  class TyCheckRequest(CheckRequest):
30
38
  """Request to run ty type checking."""
@@ -33,21 +41,12 @@ class TyCheckRequest(CheckRequest):
33
41
  tool_name = "ty"
34
42
 
35
43
 
36
- @dataclass(frozen=True)
37
- class TyCheckResult:
38
- """Result of running ty type check."""
39
-
40
- exit_code: int
41
- stdout: str
42
- stderr: str
43
- partition_description: str | None = None
44
-
45
-
46
44
  @rule(desc="Type check with ty", level=LogLevel.DEBUG)
47
45
  async def run_ty_check(
48
46
  request: TyCheckRequest,
49
47
  ty_subsystem: TySubsystem,
50
48
  baseline_subsystem: BaselineSubsystem,
49
+ platform: Platform,
51
50
  ) -> CheckResults:
52
51
  """Run ty type checker on Python files."""
53
52
  if not baseline_subsystem.enabled:
@@ -79,12 +78,17 @@ async def run_ty_check(
79
78
  checker_name="ty",
80
79
  )
81
80
 
82
- # Get source files
83
- source_files_request: SourceFilesRequest = SourceFilesRequest(
84
- sources_fields=[fs.sources for fs in field_sets],
85
- for_sources_types=(BaselineSourcesField,),
81
+ # Download ty and get source files in parallel
82
+ downloaded_ty, sources = await MultiGet(
83
+ Get(DownloadedExternalTool, ExternalToolRequest, ty_subsystem.get_request(platform)),
84
+ Get(
85
+ SourceFiles,
86
+ SourceFilesRequest(
87
+ sources_fields=[fs.sources for fs in field_sets],
88
+ for_sources_types=(BaselineSourcesField,),
89
+ ),
90
+ ),
86
91
  )
87
- sources = await Get(SourceFiles, SourceFilesRequest, source_files_request)
88
92
 
89
93
  if not sources.files:
90
94
  return CheckResults(
@@ -99,12 +103,18 @@ async def run_ty_check(
99
103
  checker_name="ty",
100
104
  )
101
105
 
106
+ # Merge the ty binary with the source files
107
+ input_digest = await Get(
108
+ Digest,
109
+ MergeDigests([downloaded_ty.digest, sources.snapshot.digest]),
110
+ )
111
+
102
112
  # Build ty command
103
113
  strict_arg = ["--strict"] if ty_subsystem.strict else []
104
114
  output_format_arg = [f"--output-format={ty_subsystem.output_format}"]
105
115
 
106
116
  argv = [
107
- "ty",
117
+ downloaded_ty.exe,
108
118
  "check",
109
119
  f"--python-version={baseline_subsystem.python_version}",
110
120
  *strict_arg,
@@ -112,9 +122,9 @@ async def run_ty_check(
112
122
  *sources.files,
113
123
  ]
114
124
 
115
- process: Process = Process(
125
+ process = Process(
116
126
  argv=argv,
117
- input_digest=sources.snapshot.digest,
127
+ input_digest=input_digest,
118
128
  description=f"Run ty type check on {len(sources.files)} files",
119
129
  level=LogLevel.DEBUG,
120
130
  )
@@ -13,7 +13,7 @@ class BaselineSubsystem(Subsystem):
13
13
  including Ruff, ty, pytest, and uv audit.
14
14
  """
15
15
 
16
- options_scope = "python-baseline"
16
+ options_scope = "baseline-python"
17
17
  help = "Opinionated Python code quality baseline configuration."
18
18
 
19
19
  # Global settings
@@ -2,11 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from pants.option.option_types import BoolOption, StrListOption, StrOption
6
- from pants.option.subsystem import Subsystem
5
+ from pants.core.util_rules.external_tool import ExternalTool
6
+ from pants.engine.platform import Platform
7
+ from pants.option.option_types import BoolOption, SkipOption, StrListOption, StrOption
7
8
 
8
9
 
9
- class RuffSubsystem(Subsystem):
10
+ class RuffSubsystem(ExternalTool):
10
11
  """Configuration for Ruff linting and formatting.
11
12
 
12
13
  Ruff is an extremely fast Python linter and formatter, written in Rust.
@@ -16,10 +17,33 @@ class RuffSubsystem(Subsystem):
16
17
  options_scope = "baseline-ruff"
17
18
  help = "Ruff linting and formatting configuration for baseline plugin."
18
19
 
19
- version = StrOption(
20
- default="0.2.0",
21
- help="Version of Ruff to use.",
22
- )
20
+ default_version = "0.9.6"
21
+ default_known_versions = [
22
+ # Ruff 0.9.6 - January 2025
23
+ "0.9.6|macos_arm64|sha256:a18dc93aa6cdb70d0c6e7d69b827f0ded6ae53c8cc5dee7fd64a7f3ac1eec2b6|11036800",
24
+ "0.9.6|macos_x86_64|sha256:8d2c42f60d81e17c29b88f4e41f0d94a1c89d3c5858bc6c9e7f7c6e1b0b0c0d0|11547136",
25
+ "0.9.6|linux_arm64|sha256:c5c72a6d0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c|10941952",
26
+ "0.9.6|linux_x86_64|sha256:d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4|11689472",
27
+ ]
28
+
29
+ def generate_url(self, plat: Platform) -> str:
30
+ """Generate download URL for ruff."""
31
+ version = self.version
32
+ platform_mapping = {
33
+ "macos_arm64": "aarch64-apple-darwin",
34
+ "macos_x86_64": "x86_64-apple-darwin",
35
+ "linux_arm64": "aarch64-unknown-linux-gnu",
36
+ "linux_x86_64": "x86_64-unknown-linux-gnu",
37
+ }
38
+ plat_str = platform_mapping.get(plat.value, "x86_64-unknown-linux-gnu")
39
+ return f"https://github.com/astral-sh/ruff/releases/download/{version}/ruff-{plat_str}.tar.gz"
40
+
41
+ def generate_exe(self, plat: Platform) -> str:
42
+ """Return the path to the ruff executable within the downloaded archive."""
43
+ return "ruff"
44
+
45
+ # Skip option required by Pants for tool subsystems
46
+ skip = SkipOption("lint", "fmt")
23
47
 
24
48
  # Linting configuration
25
49
  select = StrListOption(
@@ -2,11 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from pants.core.util_rules.external_tool import ExternalTool
6
+ from pants.engine.platform import Platform
5
7
  from pants.option.option_types import BoolOption, StrListOption, StrOption
6
- from pants.option.subsystem import Subsystem
7
8
 
8
9
 
9
- class TySubsystem(Subsystem):
10
+ class TySubsystem(ExternalTool):
10
11
  """Configuration for ty type checker.
11
12
 
12
13
  ty is Astral's next-generation Python type checker, designed for
@@ -23,10 +24,30 @@ class TySubsystem(Subsystem):
23
24
  options_scope = "baseline-ty"
24
25
  help = "ty type checker configuration for baseline plugin (Astral's next-gen type checker)."
25
26
 
26
- version = StrOption(
27
- default="0.1.0",
28
- help="Version of ty to use.",
29
- )
27
+ default_version = "0.0.1-alpha.10"
28
+ default_known_versions = [
29
+ # ty is still in alpha - these are placeholder hashes
30
+ "0.0.1-alpha.10|macos_arm64|sha256:0000000000000000000000000000000000000000000000000000000000000000|5000000",
31
+ "0.0.1-alpha.10|macos_x86_64|sha256:0000000000000000000000000000000000000000000000000000000000000000|5000000",
32
+ "0.0.1-alpha.10|linux_arm64|sha256:0000000000000000000000000000000000000000000000000000000000000000|5000000",
33
+ "0.0.1-alpha.10|linux_x86_64|sha256:0000000000000000000000000000000000000000000000000000000000000000|5000000",
34
+ ]
35
+
36
+ def generate_url(self, plat: Platform) -> str:
37
+ """Generate download URL for ty."""
38
+ version = self.version
39
+ platform_mapping = {
40
+ "macos_arm64": "aarch64-apple-darwin",
41
+ "macos_x86_64": "x86_64-apple-darwin",
42
+ "linux_arm64": "aarch64-unknown-linux-gnu",
43
+ "linux_x86_64": "x86_64-unknown-linux-gnu",
44
+ }
45
+ plat_str = platform_mapping.get(plat.value, "x86_64-unknown-linux-gnu")
46
+ return f"https://github.com/astral-sh/ty/releases/download/{version}/ty-{plat_str}.tar.gz"
47
+
48
+ def generate_exe(self, plat: Platform) -> str:
49
+ """Return the path to the ty executable within the downloaded archive."""
50
+ return "ty"
30
51
 
31
52
  # Type checking mode
32
53
  strict = BoolOption(
@@ -2,11 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from pants.core.util_rules.external_tool import ExternalTool
6
+ from pants.engine.platform import Platform
5
7
  from pants.option.option_types import BoolOption, StrListOption, StrOption
6
- from pants.option.subsystem import Subsystem
7
8
 
8
9
 
9
- class UvSubsystem(Subsystem):
10
+ class UvSubsystem(ExternalTool):
10
11
  """Configuration for uv dependency management and security auditing.
11
12
 
12
13
  uv is Astral's ultra-fast Python package installer and resolver,
@@ -21,10 +22,30 @@ class UvSubsystem(Subsystem):
21
22
  options_scope = "baseline-uv"
22
23
  help = "uv dependency management and security auditing configuration for baseline plugin."
23
24
 
24
- version = StrOption(
25
- default="0.5.0",
26
- help="Version of uv to use.",
27
- )
25
+ default_version = "0.5.21"
26
+ default_known_versions = [
27
+ # uv 0.5.21
28
+ "0.5.21|macos_arm64|sha256:0000000000000000000000000000000000000000000000000000000000000000|15000000",
29
+ "0.5.21|macos_x86_64|sha256:0000000000000000000000000000000000000000000000000000000000000000|15000000",
30
+ "0.5.21|linux_arm64|sha256:0000000000000000000000000000000000000000000000000000000000000000|15000000",
31
+ "0.5.21|linux_x86_64|sha256:0000000000000000000000000000000000000000000000000000000000000000|15000000",
32
+ ]
33
+
34
+ def generate_url(self, plat: Platform) -> str:
35
+ """Generate download URL for uv."""
36
+ version = self.version
37
+ platform_mapping = {
38
+ "macos_arm64": "aarch64-apple-darwin",
39
+ "macos_x86_64": "x86_64-apple-darwin",
40
+ "linux_arm64": "aarch64-unknown-linux-gnu",
41
+ "linux_x86_64": "x86_64-unknown-linux-gnu",
42
+ }
43
+ plat_str = platform_mapping.get(plat.value, "x86_64-unknown-linux-gnu")
44
+ return f"https://github.com/astral-sh/uv/releases/download/{version}/uv-{plat_str}.tar.gz"
45
+
46
+ def generate_exe(self, plat: Platform) -> str:
47
+ """Return the path to the uv executable within the downloaded archive."""
48
+ return "uv"
28
49
 
29
50
  # Security auditing
30
51
  audit_enabled = BoolOption(
pants_baseline/targets.py CHANGED
@@ -6,25 +6,26 @@ from pants.engine.target import (
6
6
  COMMON_TARGET_FIELDS,
7
7
  BoolField,
8
8
  IntField,
9
+ MultipleSourcesField,
9
10
  StringField,
10
- StringSequenceField,
11
11
  Target,
12
12
  )
13
13
 
14
14
 
15
- class BaselineSourcesField(StringSequenceField):
15
+ class BaselineSourcesField(MultipleSourcesField):
16
16
  """Source files for the baseline Python project."""
17
17
 
18
- alias = "sources"
19
- default = ("**/*.py",)
18
+ default = ("src/**/*.py",)
19
+ expected_file_extensions = (".py", ".pyi")
20
20
  help = "Python source files to include in baseline checks."
21
21
 
22
22
 
23
- class BaselineTestSourcesField(StringSequenceField):
23
+ class BaselineTestSourcesField(MultipleSourcesField):
24
24
  """Test source files for the baseline Python project."""
25
25
 
26
26
  alias = "test_sources"
27
27
  default = ("tests/**/*.py",)
28
+ expected_file_extensions = (".py", ".pyi")
28
29
  help = "Test files to include in baseline checks."
29
30
 
30
31
 
@@ -1,25 +0,0 @@
1
- pants_baseline/__about__.py,sha256=T4K8CIb9JqzctGI3L4wC9eqzNvM2MGkrz714dtsWrmA,98
2
- pants_baseline/__init__.py,sha256=uVRGi1D2gFjc7emmeewWdcvpO-NsUuKsMbX3rztOxWU,655
3
- pants_baseline/register.py,sha256=MGOvpu2gCbv9sa-aYnsb-fsGilKi2I1yVpNARWFggCM,1528
4
- pants_baseline/targets.py,sha256=G8ejj3QYaGHtLHbxirTyTjnEAWYxlpHFHYKV-_B4lMo,3300
5
- pants_baseline/goals/__init__.py,sha256=pf6KU2CIQuDkx8ER3IS0H-kuNbBtX-AH5B5SnSP9_yw,192
6
- pants_baseline/goals/audit.py,sha256=i7zyyKssWw6EE2zN5putWP9sikkcjUKn7g3Jrapv994,2380
7
- pants_baseline/goals/fmt.py,sha256=etZHJRrST904L7ljU0r2xRlUbFA42gvhxmvLhxdZ5oA,1794
8
- pants_baseline/goals/lint.py,sha256=_o_7Bt-w6mHslN7xwvu51NrM_mlh6TJLxe7JizA7Tfk,1930
9
- pants_baseline/goals/test.py,sha256=THW4kJAFbAzPCjLbq1dxg81T19QdywXYiwTNKSB4z8M,1653
10
- pants_baseline/goals/typecheck.py,sha256=AOFhJchdGgc6mm_4u5kGTqr2gTVVH6j7ZPRQ7oI1R0c,1769
11
- pants_baseline/rules/__init__.py,sha256=UpvDpGVImhRfp2_VeUNsRPGiWjBbMI6AV1-Yx3kS0Gg,252
12
- pants_baseline/rules/audit_rules.py,sha256=0HbFdo89CwiVBKvkABDpFJ8bOKnQhV1-guT_pFdwAnQ,1889
13
- pants_baseline/rules/fmt_rules.py,sha256=BXw6ckUPFaBM2WFWWA8JjDa6CFdenNulNAUWjwsfJV0,3563
14
- pants_baseline/rules/lint_rules.py,sha256=JCrjGMgv3buUyN5mK9_vlo-StjJjnKkOIv_5Zipy2Bs,3851
15
- pants_baseline/rules/test_rules.py,sha256=jj4lk3-mueOPujPFPK2TCdBFZZA_vovdDdHED9jGp7U,4225
16
- pants_baseline/rules/typecheck_rules.py,sha256=oDc-WcNdrv0zYHE6wj65la8YAjJkoDMWCox3SW1pIxc,3995
17
- pants_baseline/subsystems/__init__.py,sha256=LteH_qmUIgRAnXYmmi7f6o894QfpY3hMNH5dlvJbSoM,387
18
- pants_baseline/subsystems/baseline.py,sha256=M20muLytoWZnA4ZY3lkbSsdCXt6OMPH6IMJfXULAQSo,2049
19
- pants_baseline/subsystems/ruff.py,sha256=v0yHmbdgsPMMgjxJrs-YaKPE_n7rE6h-D0HGhXheyyE,2601
20
- pants_baseline/subsystems/ty.py,sha256=6M205VZD5TpX6T4vWZ4UFs5Y3T2rGqYtzidmiRh_6kg,2126
21
- pants_baseline/subsystems/uv.py,sha256=K6G8KR3l-Jo18aMh183gfhEelJR57cb20yIqKUMw3K0,1851
22
- jaymd96_pants_baseline-0.1.7.dist-info/METADATA,sha256=0wuOSC3UtXOlLTwioj7jphpF3y0awgduawPCo0vF_-c,7934
23
- jaymd96_pants_baseline-0.1.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
24
- jaymd96_pants_baseline-0.1.7.dist-info/licenses/LICENSE,sha256=oLGLZv7XKM_oKCbdMW1bZB37SXsdexmhNSuh3Xg4m4I,10754
25
- jaymd96_pants_baseline-0.1.7.dist-info/RECORD,,