• 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/codegen/thrift/scrooge/java/rules.py
1
# Copyright 2021 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.codegen.thrift.scrooge.java import symbol_mapper
×
UNCOV
8
from pants.backend.codegen.thrift.scrooge.rules import (
×
9
    GenerateScroogeThriftSourcesRequest,
10
    generate_scrooge_thrift_sources,
11
)
UNCOV
12
from pants.backend.codegen.thrift.target_types import (
×
13
    ThriftDependenciesField,
14
    ThriftSourceField,
15
    ThriftSourcesGeneratorTarget,
16
    ThriftSourceTarget,
17
)
UNCOV
18
from pants.backend.java.target_types import JavaSourceField
×
UNCOV
19
from pants.backend.scala.subsystems.scala import ScalaSubsystem
×
UNCOV
20
from pants.build_graph.address import Address
×
UNCOV
21
from pants.engine.fs import AddPrefix
×
UNCOV
22
from pants.engine.intrinsics import digest_to_snapshot
×
UNCOV
23
from pants.engine.rules import collect_rules, implicitly, rule
×
UNCOV
24
from pants.engine.target import (
×
25
    FieldSet,
26
    GeneratedSources,
27
    GenerateSourcesRequest,
28
    InferDependenciesRequest,
29
    InferredDependencies,
30
)
UNCOV
31
from pants.engine.unions import UnionRule
×
UNCOV
32
from pants.jvm.dependency_inference import artifact_mapper
×
UNCOV
33
from pants.jvm.dependency_inference.artifact_mapper import (
×
34
    AllJvmArtifactTargets,
35
    UnversionedCoordinate,
36
    find_jvm_artifacts_or_raise,
37
)
UNCOV
38
from pants.jvm.subsystems import JvmSubsystem
×
UNCOV
39
from pants.jvm.target_types import JvmResolveField, PrefixedJvmJdkField, PrefixedJvmResolveField
×
UNCOV
40
from pants.source.source_root import SourceRootRequest, get_source_root
×
UNCOV
41
from pants.util.logging import LogLevel
×
42

43

UNCOV
44
class GenerateJavaFromThriftRequest(GenerateSourcesRequest):
×
UNCOV
45
    input = ThriftSourceField
×
UNCOV
46
    output = JavaSourceField
×
47

48

UNCOV
49
@dataclass(frozen=True)
×
UNCOV
50
class ScroogeThriftJavaDependenciesInferenceFieldSet(FieldSet):
×
UNCOV
51
    required_fields = (
×
52
        ThriftDependenciesField,
53
        JvmResolveField,
54
    )
55

UNCOV
56
    dependencies: ThriftDependenciesField
×
UNCOV
57
    resolve: JvmResolveField
×
58

59

UNCOV
60
class InferScroogeThriftJavaDependencies(InferDependenciesRequest):
×
UNCOV
61
    infer_from = ScroogeThriftJavaDependenciesInferenceFieldSet
×
62

63

UNCOV
64
@rule(desc="Generate Java from Thrift with Scrooge", level=LogLevel.DEBUG)
×
UNCOV
65
async def generate_java_from_thrift_with_scrooge(
×
66
    request: GenerateJavaFromThriftRequest,
67
) -> GeneratedSources:
68
    result = await generate_scrooge_thrift_sources(
×
69
        GenerateScroogeThriftSourcesRequest(
70
            thrift_source_field=request.protocol_target[ThriftSourceField],
71
            lang_id="java",
72
            lang_name="Java",
73
        ),
74
        **implicitly(),
75
    )
76

77
    source_root = await get_source_root(SourceRootRequest.for_target(request.protocol_target))
×
78

79
    source_root_restored = (
×
80
        await digest_to_snapshot(**implicitly(AddPrefix(result.snapshot.digest, source_root.path)))
81
        if source_root.path != "."
82
        else await digest_to_snapshot(result.snapshot.digest)
83
    )
84
    return GeneratedSources(source_root_restored)
×
85

86

UNCOV
87
@dataclass(frozen=True)
×
UNCOV
88
class ScroogeThriftJavaRuntimeForResolveRequest:
×
UNCOV
89
    resolve_name: str
×
90

91

UNCOV
92
@dataclass(frozen=True)
×
UNCOV
93
class ScroogeThriftJavaRuntimeForResolve:
×
UNCOV
94
    addresses: frozenset[Address]
×
95

96

UNCOV
97
@rule
×
UNCOV
98
async def resolve_scrooge_thrift_java_runtime_for_resolve(
×
99
    request: ScroogeThriftJavaRuntimeForResolveRequest,
100
    jvm_artifact_targets: AllJvmArtifactTargets,
101
    jvm: JvmSubsystem,
102
    scala_subsystem: ScalaSubsystem,
103
) -> ScroogeThriftJavaRuntimeForResolve:
104
    scala_version = scala_subsystem.version_for_resolve(request.resolve_name)
×
105
    scala_binary_version = scala_version.binary
×
106
    addresses = find_jvm_artifacts_or_raise(
×
107
        required_coordinates=[
108
            UnversionedCoordinate(
109
                group="org.apache.thrift",
110
                artifact="libthrift",
111
            ),
112
            UnversionedCoordinate(
113
                group="com.twitter",
114
                artifact=f"scrooge-core_{scala_binary_version}",
115
            ),
116
        ],
117
        resolve=request.resolve_name,
118
        jvm_artifact_targets=jvm_artifact_targets,
119
        jvm=jvm,
120
        subsystem="the Scrooge Java Thrift runtime",
121
        target_type="thrift_sources",
122
    )
123
    return ScroogeThriftJavaRuntimeForResolve(addresses)
×
124

125

UNCOV
126
@rule
×
UNCOV
127
async def inject_scrooge_thrift_java_dependencies(
×
128
    request: InferScroogeThriftJavaDependencies, jvm: JvmSubsystem
129
) -> InferredDependencies:
130
    resolve = request.field_set.resolve.normalized_value(jvm)
×
131
    dependencies_info = await resolve_scrooge_thrift_java_runtime_for_resolve(
×
132
        ScroogeThriftJavaRuntimeForResolveRequest(resolve), **implicitly()
133
    )
134
    return InferredDependencies(dependencies_info.addresses)
×
135

136

UNCOV
137
def rules():
×
UNCOV
138
    return (
×
139
        *collect_rules(),
140
        *symbol_mapper.rules(),
141
        UnionRule(GenerateSourcesRequest, GenerateJavaFromThriftRequest),
142
        UnionRule(InferDependenciesRequest, InferScroogeThriftJavaDependencies),
143
        ThriftSourceTarget.register_plugin_field(PrefixedJvmJdkField),
144
        ThriftSourcesGeneratorTarget.register_plugin_field(PrefixedJvmJdkField),
145
        ThriftSourceTarget.register_plugin_field(PrefixedJvmResolveField),
146
        ThriftSourcesGeneratorTarget.register_plugin_field(PrefixedJvmResolveField),
147
        # Rules to avoid rule graph errors.
148
        *artifact_mapper.rules(),
149
    )
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