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

pantsbuild / pants / 19015773527

02 Nov 2025 05:33PM UTC coverage: 17.872% (-62.4%) from 80.3%
19015773527

Pull #22816

github

web-flow
Merge a12d75757 into 6c024e162
Pull Request #22816: Update Pants internal Python to 3.14

4 of 5 new or added lines in 3 files covered. (80.0%)

28452 existing lines in 683 files now uncovered.

9831 of 55007 relevant lines covered (17.87%)

0.18 hits per line

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

0.0
/src/python/pants/backend/javascript/nodejs_project_environment.py
1
# Copyright 2023 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
import os.path
×
UNCOV
6
from collections.abc import Iterable
×
UNCOV
7
from dataclasses import dataclass, field
×
8

UNCOV
9
from pants.backend.javascript import package_json, resolve
×
UNCOV
10
from pants.backend.javascript.nodejs_project import NodeJSProject
×
UNCOV
11
from pants.backend.javascript.package_json import (
×
12
    NodePackageExtraEnvVarsField,
13
    NodePackageNameField,
14
    OwningNodePackage,
15
    OwningNodePackageRequest,
16
    find_owning_package,
17
)
UNCOV
18
from pants.backend.javascript.resolve import (
×
19
    ChosenNodeResolve,
20
    RequestNodeResolve,
21
    resolve_for_package,
22
)
UNCOV
23
from pants.backend.javascript.subsystems import nodejs
×
UNCOV
24
from pants.backend.javascript.subsystems.nodejs import NodeJSToolProcess, setup_node_tool_process
×
UNCOV
25
from pants.build_graph.address import Address
×
UNCOV
26
from pants.core.util_rules.env_vars import environment_vars_subset
×
UNCOV
27
from pants.engine.env_vars import EnvironmentVarsRequest
×
UNCOV
28
from pants.engine.internals.native_engine import EMPTY_DIGEST, Digest, MergeDigests
×
UNCOV
29
from pants.engine.internals.selectors import concurrently
×
UNCOV
30
from pants.engine.intrinsics import merge_digests, path_globs_to_digest
×
UNCOV
31
from pants.engine.process import Process
×
UNCOV
32
from pants.engine.rules import Rule, collect_rules, implicitly, rule
×
UNCOV
33
from pants.engine.target import Target
×
UNCOV
34
from pants.engine.unions import UnionRule
×
UNCOV
35
from pants.util.dirutil import fast_relpath
×
UNCOV
36
from pants.util.frozendict import FrozenDict
×
UNCOV
37
from pants.util.logging import LogLevel
×
38

39

UNCOV
40
@dataclass(frozen=True)
×
UNCOV
41
class NodeJSProjectEnvironmentRequest:
×
UNCOV
42
    address: Address
×
43

44

UNCOV
45
@dataclass(frozen=True)
×
UNCOV
46
class NodeJsProjectEnvironment:
×
UNCOV
47
    resolve: ChosenNodeResolve
×
UNCOV
48
    package: OwningNodePackage | None = None
×
49

UNCOV
50
    @classmethod
×
UNCOV
51
    def from_root(cls, project: NodeJSProject) -> NodeJsProjectEnvironment:
×
52
        return cls(resolve=ChosenNodeResolve(project), package=None)
×
53

UNCOV
54
    @property
×
UNCOV
55
    def project(self) -> NodeJSProject:
×
56
        return self.resolve.project
×
57

UNCOV
58
    @property
×
UNCOV
59
    def root_dir(self) -> str:
×
60
        return self.project.root_dir
×
61

UNCOV
62
    @property
×
UNCOV
63
    def node_modules_directories(self) -> Iterable[str]:
×
64
        yield "node_modules"
×
65
        if self.package and not self.project.single_workspace:
×
66
            yield os.path.join(self.relative_workspace_directory(), "node_modules")
×
67

UNCOV
68
    @property
×
UNCOV
69
    def target(self) -> Target | None:
×
70
        if self.package:
×
71
            return self.package.target
×
72
        else:
73
            return None
×
74

UNCOV
75
    def package_dir(self) -> str:
×
76
        if self.package and not self.project.single_workspace:
×
77
            return self.ensure_target().residence_dir
×
78
        else:
79
            return self.root_dir
×
80

UNCOV
81
    def relative_workspace_directory(self) -> str:
×
82
        target = self.ensure_target()
×
83
        from_root_to_workspace = fast_relpath(target.residence_dir, self.root_dir)
×
84
        return from_root_to_workspace
×
85

UNCOV
86
    def ensure_target(self) -> Target:
×
87
        if self.target:
×
88
            return self.target
×
89
        raise ValueError("")
×
90

91

UNCOV
92
@dataclass(frozen=True)
×
UNCOV
93
class NodeJsProjectEnvironmentProcess:
×
UNCOV
94
    env: NodeJsProjectEnvironment
×
UNCOV
95
    args: Iterable[str]
×
UNCOV
96
    description: str
×
UNCOV
97
    level: LogLevel = LogLevel.INFO
×
UNCOV
98
    input_digest: Digest = EMPTY_DIGEST
×
UNCOV
99
    output_files: tuple[str, ...] = ()
×
UNCOV
100
    output_directories: tuple[str, ...] = ()
×
UNCOV
101
    per_package_caches: FrozenDict[str, str] = field(default_factory=FrozenDict)
×
UNCOV
102
    project_caches: FrozenDict[str, str] = field(default_factory=FrozenDict)
×
UNCOV
103
    timeout_seconds: int | None = None
×
UNCOV
104
    extra_env: FrozenDict[str, str] = field(default_factory=FrozenDict)
×
105

UNCOV
106
    def targeted_args(self) -> tuple[str, ...]:
×
107
        if (
×
108
            not self.env.project.single_workspace
109
            and self.env.target
110
            and self.env.root_dir != self.env.package_dir()
111
        ):
112
            target = self.env.ensure_target()
×
113
            return (
×
114
                self.env.project.workspace_specifier_arg,
115
                target[NodePackageNameField].value,
116
                *self.args,
117
            )
118
        else:
119
            return tuple(self.args)
×
120

121

UNCOV
122
@rule(desc="Assembling nodejs project environment")
×
UNCOV
123
async def get_nodejs_environment(req: NodeJSProjectEnvironmentRequest) -> NodeJsProjectEnvironment:
×
124
    node_resolve, owning_tgt = await concurrently(
×
125
        resolve_for_package(RequestNodeResolve(req.address), **implicitly()),
126
        find_owning_package(OwningNodePackageRequest(req.address)),
127
    )
128
    assert owning_tgt.target, f"Already ensured to exist by {ChosenNodeResolve.__name__}."
×
129

130
    return NodeJsProjectEnvironment(node_resolve, owning_tgt)
×
131

132

UNCOV
133
@rule
×
UNCOV
134
async def setup_nodejs_project_environment_process(
×
135
    req: NodeJsProjectEnvironmentProcess,
136
    nodejs: nodejs.NodeJS,
137
) -> Process:
138
    target_env_vars = (
×
139
        req.env.target.get(NodePackageExtraEnvVarsField).value or () if req.env.target else ()
140
    )
141

142
    lockfile_digest, project_digest, subsystem_env_vars, env_vars = await concurrently(
×
143
        path_globs_to_digest(req.env.resolve.get_lockfile_glob()),
144
        merge_digests(req.env.project.get_project_digest()),
145
        environment_vars_subset(EnvironmentVarsRequest(nodejs.extra_env_vars), **implicitly()),
146
        environment_vars_subset(EnvironmentVarsRequest(target_env_vars), **implicitly()),
147
    )
148
    merged = await merge_digests(MergeDigests((req.input_digest, lockfile_digest, project_digest)))
×
149

150
    args = req.targeted_args()
×
151
    output_files = req.output_files
×
152
    output_directories = req.output_directories
×
153
    per_package_caches = FrozenDict(
×
154
        {
155
            key: os.path.join(req.env.package_dir(), value)
156
            for key, value in req.per_package_caches.items()
157
        }
158
    )
159
    append_only_caches: FrozenDict[str, str] = FrozenDict(
×
160
        **per_package_caches, **req.project_caches, **req.env.project.extra_caches()
161
    )
162

163
    return await setup_node_tool_process(
×
164
        **implicitly(
165
            NodeJSToolProcess(
166
                tool=req.env.project.package_manager.name,
167
                tool_version=req.env.project.package_manager.version,
168
                args=args,
169
                description=req.description,
170
                level=req.level,
171
                input_digest=merged,
172
                working_directory=req.env.root_dir,
173
                output_files=output_files,
174
                output_directories=output_directories,
175
                append_only_caches=append_only_caches,
176
                timeout_seconds=req.timeout_seconds,
177
                project_digest=project_digest,
178
                extra_env=FrozenDict(
179
                    {
180
                        **subsystem_env_vars,
181
                        **env_vars,
182
                        **req.extra_env,
183
                        **req.env.project.extra_env(),
184
                    }
185
                ),
186
            )
187
        )
188
    )
189

190

UNCOV
191
def rules() -> Iterable[Rule | UnionRule]:
×
UNCOV
192
    return [*collect_rules(), *nodejs.rules(), *resolve.rules(), *package_json.rules()]
×
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