• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 20147226056

11 Dec 2025 08:58PM UTC coverage: 78.827% (-1.5%) from 80.293%
20147226056

push

github

web-flow
Forwarded the `style` and `complete-platform` args from pants.toml to PEX (#22910)

## Context

After Apple switched to the `arm64` architecture, some package
publishers stopped releasing `x86_64` variants of their packages for
`darwin`. As a result, generating a universal lockfile now fails because
no single package version is compatible with both `x86_64` and `arm64`
on `darwin`.

The solution is to use the `--style` and `--complete-platform` flags
with PEX. For example:
```
pex3 lock create \
    --style strict \
    --complete-platform 3rdparty/platforms/manylinux_2_28_aarch64.json \
    --complete-platform 3rdparty/platforms/macosx_26_0_arm64.json \
    -r 3rdparty/python/requirements_pyarrow.txt \
    -o python-pyarrow.lock
```

See the Slack discussion here:
https://pantsbuild.slack.com/archives/C046T6T9U/p1760098582461759

## Reproduction

* `BUILD`
```
python_requirement(
    name="awswrangler",
    requirements=["awswrangler==3.12.1"],
    resolve="awswrangler",
)
```
* Run `pants generate-lockfiles --resolve=awswrangler` on macOS with an
`arm64` CPU
```
pip: ERROR: Cannot install awswrangler==3.12.1 because these package versions have conflicting dependencies.
pip: ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts
pip:  
pip:  The conflict is caused by:
pip:      awswrangler 3.12.1 depends on pyarrow<18.0.0 and >=8.0.0; sys_platform == "darwin" and platform_machine == "x86_64"
pip:      awswrangler 3.12.1 depends on pyarrow<21.0.0 and >=18.0.0; sys_platform != "darwin" or platform_machine != "x86_64"
pip:  
pip:  Additionally, some packages in these conflicts have no matching distributions available for your environment:
pip:      pyarrow
pip:  
pip:  To fix this you could try to:
pip:  1. loosen the range of package versions you've specified
pip:  2. remove package versions to allow pip to attempt to solve the dependency conflict
```

## Implementation
... (continued)

77 of 100 new or added lines in 6 files covered. (77.0%)

868 existing lines in 42 files now uncovered.

74471 of 94474 relevant lines covered (78.83%)

3.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/python/pants/backend/go/util_rules/coverage_output.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
UNCOV
3
from __future__ import annotations
×
4

UNCOV
5
from dataclasses import dataclass
×
6

UNCOV
7
from pants.backend.go.subsystems.gotest import GoTestSubsystem
×
UNCOV
8
from pants.backend.go.util_rules import coverage_html
×
UNCOV
9
from pants.backend.go.util_rules.coverage import GoCoverageData
×
UNCOV
10
from pants.backend.go.util_rules.coverage_html import (
×
11
    RenderGoCoverageProfileToHtmlRequest,
12
    render_go_coverage_profile_to_html,
13
)
UNCOV
14
from pants.core.goals.test import CoverageDataCollection, CoverageReports, FilesystemCoverageReport
×
UNCOV
15
from pants.core.util_rules import distdir
×
UNCOV
16
from pants.core.util_rules.distdir import DistDir
×
UNCOV
17
from pants.engine.engine_aware import EngineAwareParameter
×
UNCOV
18
from pants.engine.fs import CreateDigest, FileContent
×
UNCOV
19
from pants.engine.internals.selectors import concurrently
×
UNCOV
20
from pants.engine.intrinsics import digest_to_snapshot, get_digest_contents
×
UNCOV
21
from pants.engine.rules import collect_rules, implicitly, rule
×
UNCOV
22
from pants.engine.unions import UnionRule
×
UNCOV
23
from pants.util.logging import LogLevel
×
24

25

UNCOV
26
class GoCoverageDataCollection(CoverageDataCollection):
×
UNCOV
27
    element_type = GoCoverageData
×
28

29

UNCOV
30
@dataclass(frozen=True)
×
UNCOV
31
class RenderGoCoverageReportRequest(EngineAwareParameter):
×
UNCOV
32
    raw_report: GoCoverageData
×
33

UNCOV
34
    def debug_hint(self) -> str | None:
×
35
        return self.raw_report.import_path
×
36

37

UNCOV
38
@dataclass(frozen=True)
×
UNCOV
39
class RenderGoCoverageReportResult:
×
UNCOV
40
    coverage_report: FilesystemCoverageReport
×
UNCOV
41
    html_report: FilesystemCoverageReport | None = None
×
42

43

UNCOV
44
@rule
×
UNCOV
45
async def go_render_coverage_report(
×
46
    request: RenderGoCoverageReportRequest,
47
    distdir_value: DistDir,
48
    go_test_subsystem: GoTestSubsystem,
49
) -> RenderGoCoverageReportResult:
50
    output_dir = go_test_subsystem.coverage_output_dir(
×
51
        distdir=distdir_value,
52
        address=request.raw_report.pkg_target_address,
53
        import_path=request.raw_report.import_path,
54
    )
55
    snapshot, digest_contents = await concurrently(
×
56
        digest_to_snapshot(request.raw_report.coverage_digest),
57
        get_digest_contents(request.raw_report.coverage_digest),
58
    )
59

60
    html_coverage_report: FilesystemCoverageReport | None = None
×
61
    if go_test_subsystem.coverage_html:
×
62
        html_result = await render_go_coverage_profile_to_html(
×
63
            RenderGoCoverageProfileToHtmlRequest(
64
                raw_coverage_profile=digest_contents[0].content,
65
                description_of_origin=f"Go package with import path `{request.raw_report.import_path}`",
66
                sources_digest=request.raw_report.sources_digest,
67
                sources_dir_path=request.raw_report.sources_dir_path,
68
            )
69
        )
70
        html_report_snapshot = await digest_to_snapshot(
×
71
            **implicitly(
72
                CreateDigest(
73
                    [
74
                        FileContent(
75
                            path="coverage.html",
76
                            content=html_result.html_output,
77
                        )
78
                    ]
79
                )
80
            )
81
        )
82

83
        html_coverage_report = FilesystemCoverageReport(
×
84
            coverage_insufficient=False,
85
            result_snapshot=html_report_snapshot,
86
            directory_to_materialize_to=output_dir,
87
            report_file=output_dir / "coverage.html",
88
            report_type="go_cover_html",
89
        )
90

91
    coverage_report = FilesystemCoverageReport(
×
92
        coverage_insufficient=False,
93
        result_snapshot=snapshot,
94
        directory_to_materialize_to=output_dir,
95
        report_file=output_dir / "cover.out",
96
        report_type="go_cover",
97
    )
98
    return RenderGoCoverageReportResult(
×
99
        coverage_report=coverage_report,
100
        html_report=html_coverage_report,
101
    )
102

103

UNCOV
104
@rule(desc="Merge Go coverage data", level=LogLevel.DEBUG)
×
UNCOV
105
async def go_gather_coverage_reports(
×
106
    raw_coverage_reports: GoCoverageDataCollection,
107
) -> CoverageReports:
108
    coverage_report_results = await concurrently(
×
109
        go_render_coverage_report(
110
            RenderGoCoverageReportRequest(
111
                raw_report=raw_coverage_report,
112
            ),
113
            **implicitly(),
114
        )
115
        for raw_coverage_report in raw_coverage_reports
116
    )
117

118
    coverage_reports = []
×
119
    for result in coverage_report_results:
×
120
        coverage_reports.append(result.coverage_report)
×
121
        if result.html_report:
×
122
            coverage_reports.append(result.html_report)
×
123

124
    return CoverageReports(reports=tuple(coverage_reports))
×
125

126

UNCOV
127
def rules():
×
UNCOV
128
    return (
×
129
        *collect_rules(),
130
        *coverage_html.rules(),
131
        *distdir.rules(),
132
        UnionRule(CoverageDataCollection, GoCoverageDataCollection),
133
    )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc