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

pantsbuild / pants / 20438429929

22 Dec 2025 04:55PM UTC coverage: 80.287% (+0.003%) from 80.284%
20438429929

Pull #22934

github

web-flow
Merge b49c09e21 into 06f105be8
Pull Request #22934: feat(go): add multi-module support to golangci-lint plugin and upgrade to v2

37 of 62 new or added lines in 3 files covered. (59.68%)

183 existing lines in 9 files now uncovered.

78528 of 97809 relevant lines covered (80.29%)

3.36 hits per line

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

93.82
/src/python/pants/backend/python/util_rules/lockfile_metadata.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
12✔
5

6
from collections.abc import Iterable
12✔
7
from dataclasses import dataclass
12✔
8
from enum import Enum
12✔
9
from typing import Any, cast
12✔
10

11
from pants.backend.python.util_rules.interpreter_constraints import InterpreterConstraints
12✔
12
from pants.core.util_rules.lockfile_metadata import (
12✔
13
    LockfileMetadata,
14
    LockfileMetadataValidation,
15
    LockfileScope,
16
    _get_metadata,
17
    lockfile_metadata_registrar,
18
)
19
from pants.util.pip_requirement import PipRequirement
12✔
20

21
_python_lockfile_metadata = lockfile_metadata_registrar(LockfileScope.PYTHON)
12✔
22

23

24
class InvalidPythonLockfileReason(Enum):
12✔
25
    INVALIDATION_DIGEST_MISMATCH = "invalidation_digest_mismatch"
12✔
26
    INTERPRETER_CONSTRAINTS_MISMATCH = "interpreter_constraints_mismatch"
12✔
27
    REQUIREMENTS_MISMATCH = "requirements_mismatch"
12✔
28
    MANYLINUX_MISMATCH = "manylinux_mismatch"
12✔
29
    CONSTRAINTS_FILE_MISMATCH = "constraints_file_mismatch"
12✔
30
    ONLY_BINARY_MISMATCH = "only_binary_mismatch"
12✔
31
    NO_BINARY_MISMATCH = "no_binary_mismatch"
12✔
32
    EXCLUDES_MISMATCH = "excludes_mismatch"
12✔
33
    OVERRIDES_MISMATCH = "overrides_mismatch"
12✔
34
    SOURCES_MISMATCH = "sources_mismatch"
12✔
35
    LOCK_STYLE_MISMATCH = "lock_style_mismatch"
12✔
36
    COMPLETE_PLATFORMS_MISMATCH = "complete_platforms_mismatch"
12✔
37

38

39
@dataclass(frozen=True)
12✔
40
class PythonLockfileMetadata(LockfileMetadata):
12✔
41
    scope = LockfileScope.PYTHON
12✔
42

43
    valid_for_interpreter_constraints: InterpreterConstraints
12✔
44

45
    @staticmethod
12✔
46
    def new(
12✔
47
        *,
48
        valid_for_interpreter_constraints: InterpreterConstraints,
49
        requirements: set[PipRequirement],
50
        manylinux: str | None,
51
        requirement_constraints: set[PipRequirement],
52
        only_binary: set[str],
53
        no_binary: set[str],
54
        excludes: set[str],
55
        overrides: set[str],
56
        sources: set[str],
57
        lock_style: str,
58
        complete_platforms: tuple[str, ...],
59
    ) -> PythonLockfileMetadata:
60
        """Call the most recent version of the `LockfileMetadata` class to construct a concrete
61
        instance.
62

63
        This static method should be used in place of the `LockfileMetadata` constructor. This gives
64
        calling sites a predictable method to call to construct a new `LockfileMetadata` for
65
        writing, while still allowing us to support _reading_ older, deprecated metadata versions.
66
        """
67

68
        return PythonLockfileMetadataV6(
2✔
69
            valid_for_interpreter_constraints,
70
            requirements,
71
            manylinux=manylinux,
72
            requirement_constraints=requirement_constraints,
73
            only_binary=only_binary,
74
            no_binary=no_binary,
75
            excludes=excludes,
76
            overrides=overrides,
77
            sources=sources,
78
            lock_style=lock_style,
79
            complete_platforms=complete_platforms,
80
        )
81

82
    @staticmethod
12✔
83
    def metadata_location_for_lockfile(lockfile_location: str) -> str:
12✔
UNCOV
84
        return f"{lockfile_location}.metadata"
×
85

86
    @classmethod
12✔
87
    def additional_header_attrs(cls, instance: LockfileMetadata) -> dict[Any, Any]:
12✔
88
        instance = cast(PythonLockfileMetadata, instance)
2✔
89
        return {
2✔
90
            "valid_for_interpreter_constraints": [
91
                str(ic) for ic in instance.valid_for_interpreter_constraints
92
            ]
93
        }
94

95
    def is_valid_for(
12✔
96
        self,
97
        *,
98
        expected_invalidation_digest: str | None,
99
        user_interpreter_constraints: InterpreterConstraints,
100
        interpreter_universe: Iterable[str],
101
        user_requirements: Iterable[PipRequirement],
102
        manylinux: str | None,
103
        requirement_constraints: Iterable[PipRequirement],
104
        only_binary: Iterable[str],
105
        no_binary: Iterable[str],
106
        excludes: Iterable[str],
107
        overrides: Iterable[str],
108
        sources: Iterable[str],
109
        lock_style: str | None,
110
        complete_platforms: Iterable[str],
111
    ) -> LockfileMetadataValidation:
112
        """Returns Truthy if this `PythonLockfileMetadata` can be used in the current execution
113
        context."""
114

UNCOV
115
        raise NotImplementedError("call `is_valid_for` on subclasses only")
×
116

117

118
@_python_lockfile_metadata(1)
12✔
119
@dataclass(frozen=True)
12✔
120
class PythonLockfileMetadataV1(PythonLockfileMetadata):
12✔
121
    requirements_invalidation_digest: str
12✔
122

123
    @classmethod
12✔
124
    def _from_json_dict(
12✔
125
        cls: type[PythonLockfileMetadataV1],
126
        json_dict: dict[Any, Any],
127
        lockfile_description: str,
128
        error_suffix: str,
129
    ) -> PythonLockfileMetadataV1:
130
        metadata = _get_metadata(json_dict, lockfile_description, error_suffix)
1✔
131

132
        interpreter_constraints = metadata(
1✔
133
            "valid_for_interpreter_constraints", InterpreterConstraints, InterpreterConstraints
134
        )
135
        requirements_digest = metadata("requirements_invalidation_digest", str, None)
1✔
136

137
        return PythonLockfileMetadataV1(interpreter_constraints, requirements_digest)
1✔
138

139
    @classmethod
12✔
140
    def additional_header_attrs(cls, instance: LockfileMetadata) -> dict[Any, Any]:
12✔
UNCOV
141
        instance = cast(PythonLockfileMetadataV1, instance)
×
UNCOV
142
        return {"requirements_invalidation_digest": instance.requirements_invalidation_digest}
×
143

144
    def is_valid_for(
12✔
145
        self,
146
        *,
147
        expected_invalidation_digest: str | None,
148
        user_interpreter_constraints: InterpreterConstraints,
149
        interpreter_universe: Iterable[str],
150
        # Everything below is not used by v1.
151
        user_requirements: Iterable[PipRequirement],
152
        manylinux: str | None,
153
        requirement_constraints: Iterable[PipRequirement],
154
        only_binary: Iterable[str],
155
        no_binary: Iterable[str],
156
        excludes: Iterable[str],
157
        overrides: Iterable[str],
158
        sources: Iterable[str],
159
        lock_style: str | None,
160
        complete_platforms: Iterable[str],
161
    ) -> LockfileMetadataValidation:
162
        failure_reasons: set[InvalidPythonLockfileReason] = set()
1✔
163

164
        if expected_invalidation_digest is None:
1✔
UNCOV
165
            return LockfileMetadataValidation(failure_reasons)
×
166

167
        if self.requirements_invalidation_digest != expected_invalidation_digest:
1✔
168
            failure_reasons.add(InvalidPythonLockfileReason.INVALIDATION_DIGEST_MISMATCH)
1✔
169

170
        if not self.valid_for_interpreter_constraints.contains(
1✔
171
            user_interpreter_constraints, interpreter_universe
172
        ):
173
            failure_reasons.add(InvalidPythonLockfileReason.INTERPRETER_CONSTRAINTS_MISMATCH)
1✔
174

175
        return LockfileMetadataValidation(failure_reasons)
1✔
176

177

178
@_python_lockfile_metadata(2)
12✔
179
@dataclass(frozen=True)
12✔
180
class PythonLockfileMetadataV2(PythonLockfileMetadata):
12✔
181
    """Lockfile version that permits specifying a requirements as a set rather than a digest.
182

183
    Validity is tested by the set of requirements strings being the same in the user requirements as
184
    those in the stored requirements.
185
    """
186

187
    requirements: set[PipRequirement]
12✔
188

189
    @classmethod
12✔
190
    def _from_json_dict(
12✔
191
        cls: type[PythonLockfileMetadataV2],
192
        json_dict: dict[Any, Any],
193
        lockfile_description: str,
194
        error_suffix: str,
195
    ) -> PythonLockfileMetadataV2:
196
        metadata = _get_metadata(json_dict, lockfile_description, error_suffix)
1✔
197

198
        requirements = metadata(
1✔
199
            "generated_with_requirements",
200
            set[PipRequirement],
201
            lambda l: {
202
                PipRequirement.parse(i, description_of_origin=lockfile_description) for i in l
203
            },
204
        )
205
        interpreter_constraints = metadata(
1✔
206
            "valid_for_interpreter_constraints", InterpreterConstraints, InterpreterConstraints
207
        )
208

209
        return PythonLockfileMetadataV2(interpreter_constraints, requirements)
1✔
210

211
    @classmethod
12✔
212
    def additional_header_attrs(cls, instance: LockfileMetadata) -> dict[Any, Any]:
12✔
213
        instance = cast(PythonLockfileMetadataV2, instance)
2✔
214
        # Requirements need to be stringified then sorted so that tests are deterministic. Sorting
215
        # followed by stringifying does not produce a meaningful result.
216
        return {"generated_with_requirements": (sorted(str(i) for i in instance.requirements))}
2✔
217

218
    def is_valid_for(
12✔
219
        self,
220
        *,
221
        expected_invalidation_digest: str | None,  # Not used by V2.
222
        user_interpreter_constraints: InterpreterConstraints,
223
        interpreter_universe: Iterable[str],
224
        user_requirements: Iterable[PipRequirement],
225
        # Everything below is not used by V2.
226
        manylinux: str | None,
227
        requirement_constraints: Iterable[PipRequirement],
228
        only_binary: Iterable[str],
229
        no_binary: Iterable[str],
230
        excludes: Iterable[str],
231
        overrides: Iterable[str],
232
        sources: Iterable[str],
233
        lock_style: str | None,
234
        complete_platforms: Iterable[str],
235
    ) -> LockfileMetadataValidation:
236
        failure_reasons = set()
2✔
237
        if not set(user_requirements).issubset(self.requirements):
2✔
238
            failure_reasons.add(InvalidPythonLockfileReason.REQUIREMENTS_MISMATCH)
2✔
239

240
        if not self.valid_for_interpreter_constraints.contains(
2✔
241
            user_interpreter_constraints, interpreter_universe
242
        ):
243
            failure_reasons.add(InvalidPythonLockfileReason.INTERPRETER_CONSTRAINTS_MISMATCH)
2✔
244

245
        return LockfileMetadataValidation(failure_reasons)
2✔
246

247

248
@_python_lockfile_metadata(3)
12✔
249
@dataclass(frozen=True)
12✔
250
class PythonLockfileMetadataV3(PythonLockfileMetadataV2):
12✔
251
    """Lockfile version that considers constraints files."""
252

253
    manylinux: str | None
12✔
254
    requirement_constraints: set[PipRequirement]
12✔
255
    only_binary: set[str]
12✔
256
    no_binary: set[str]
12✔
257

258
    @classmethod
12✔
259
    def _from_json_dict(
12✔
260
        cls: type[PythonLockfileMetadataV3],
261
        json_dict: dict[Any, Any],
262
        lockfile_description: str,
263
        error_suffix: str,
264
    ) -> PythonLockfileMetadataV3:
265
        v2_metadata = super()._from_json_dict(json_dict, lockfile_description, error_suffix)
1✔
266
        metadata = _get_metadata(json_dict, lockfile_description, error_suffix)
1✔
267
        manylinux = metadata("manylinux", str, lambda l: l)
1✔
268
        requirement_constraints = metadata(
1✔
269
            "requirement_constraints",
270
            set[PipRequirement],
271
            lambda l: {
272
                PipRequirement.parse(i, description_of_origin=lockfile_description) for i in l
273
            },
274
        )
275
        only_binary = metadata("only_binary", set[str], lambda l: set(l))
1✔
276
        no_binary = metadata("no_binary", set[str], lambda l: set(l))
1✔
277

278
        return PythonLockfileMetadataV3(
1✔
279
            valid_for_interpreter_constraints=v2_metadata.valid_for_interpreter_constraints,
280
            requirements=v2_metadata.requirements,
281
            manylinux=manylinux,
282
            requirement_constraints=requirement_constraints,
283
            only_binary=only_binary,
284
            no_binary=no_binary,
285
        )
286

287
    @classmethod
12✔
288
    def additional_header_attrs(cls, instance: LockfileMetadata) -> dict[Any, Any]:
12✔
289
        instance = cast(PythonLockfileMetadataV3, instance)
2✔
290
        return {
2✔
291
            "manylinux": instance.manylinux,
292
            "requirement_constraints": sorted(str(i) for i in instance.requirement_constraints),
293
            "only_binary": sorted(instance.only_binary),
294
            "no_binary": sorted(instance.no_binary),
295
        }
296

297
    def is_valid_for(
12✔
298
        self,
299
        *,
300
        expected_invalidation_digest: str | None,  # Validation digests are not used by V2.
301
        user_interpreter_constraints: InterpreterConstraints,
302
        interpreter_universe: Iterable[str],
303
        user_requirements: Iterable[PipRequirement],
304
        manylinux: str | None,
305
        requirement_constraints: Iterable[PipRequirement],
306
        only_binary: Iterable[str],
307
        no_binary: Iterable[str],
308
        # not used for V3
309
        excludes: Iterable[str],
310
        overrides: Iterable[str],
311
        sources: Iterable[str],
312
        lock_style: str | None,
313
        complete_platforms: Iterable[str],
314
    ) -> LockfileMetadataValidation:
315
        failure_reasons = (
2✔
316
            super()
317
            .is_valid_for(
318
                expected_invalidation_digest=expected_invalidation_digest,
319
                user_interpreter_constraints=user_interpreter_constraints,
320
                interpreter_universe=interpreter_universe,
321
                user_requirements=user_requirements,
322
                manylinux=manylinux,
323
                requirement_constraints=requirement_constraints,
324
                only_binary=only_binary,
325
                no_binary=no_binary,
326
                excludes=excludes,
327
                overrides=overrides,
328
                sources=sources,
329
                lock_style=lock_style,
330
                complete_platforms=complete_platforms,
331
            )
332
            .failure_reasons
333
        )
334

335
        if self.manylinux != manylinux:
2✔
336
            failure_reasons.add(InvalidPythonLockfileReason.MANYLINUX_MISMATCH)
2✔
337
        if self.requirement_constraints != set(requirement_constraints):
2✔
338
            failure_reasons.add(InvalidPythonLockfileReason.CONSTRAINTS_FILE_MISMATCH)
2✔
339
        if self.only_binary != set(only_binary):
2✔
340
            failure_reasons.add(InvalidPythonLockfileReason.ONLY_BINARY_MISMATCH)
2✔
341
        if self.no_binary != set(no_binary):
2✔
342
            failure_reasons.add(InvalidPythonLockfileReason.NO_BINARY_MISMATCH)
2✔
343

344
        return LockfileMetadataValidation(failure_reasons)
2✔
345

346

347
@_python_lockfile_metadata(4)
12✔
348
@dataclass(frozen=True)
12✔
349
class PythonLockfileMetadataV4(PythonLockfileMetadataV3):
12✔
350
    """Lockfile version with excludes/overrides."""
351

352
    excludes: set[str]
12✔
353
    overrides: set[str]
12✔
354

355
    @classmethod
12✔
356
    def _from_json_dict(
12✔
357
        cls: type[PythonLockfileMetadataV4],
358
        json_dict: dict[Any, Any],
359
        lockfile_description: str,
360
        error_suffix: str,
361
    ) -> PythonLockfileMetadataV4:
362
        v3_metadata = super()._from_json_dict(json_dict, lockfile_description, error_suffix)
1✔
363
        metadata = _get_metadata(json_dict, lockfile_description, error_suffix)
1✔
364

365
        excludes = metadata("excludes", set[str], lambda l: set(l))
1✔
366
        overrides = metadata("overrides", set[str], lambda l: set(l))
1✔
367

368
        return PythonLockfileMetadataV4(
1✔
369
            valid_for_interpreter_constraints=v3_metadata.valid_for_interpreter_constraints,
370
            requirements=v3_metadata.requirements,
371
            manylinux=v3_metadata.manylinux,
372
            requirement_constraints=v3_metadata.requirement_constraints,
373
            only_binary=v3_metadata.only_binary,
374
            no_binary=v3_metadata.no_binary,
375
            excludes=excludes,
376
            overrides=overrides,
377
        )
378

379
    @classmethod
12✔
380
    def additional_header_attrs(cls, instance: LockfileMetadata) -> dict[Any, Any]:
12✔
381
        instance = cast(PythonLockfileMetadataV4, instance)
2✔
382
        return {
2✔
383
            "excludes": sorted(instance.excludes),
384
            "overrides": sorted(instance.overrides),
385
        }
386

387
    def is_valid_for(
12✔
388
        self,
389
        *,
390
        expected_invalidation_digest: str | None,
391
        user_interpreter_constraints: InterpreterConstraints,
392
        interpreter_universe: Iterable[str],
393
        user_requirements: Iterable[PipRequirement],
394
        manylinux: str | None,
395
        requirement_constraints: Iterable[PipRequirement],
396
        only_binary: Iterable[str],
397
        no_binary: Iterable[str],
398
        excludes: Iterable[str],
399
        overrides: Iterable[str],
400
        # not used for V4
401
        sources: Iterable[str],
402
        lock_style: str | None,
403
        complete_platforms: Iterable[str],
404
    ) -> LockfileMetadataValidation:
405
        failure_reasons = (
1✔
406
            super()
407
            .is_valid_for(
408
                expected_invalidation_digest=expected_invalidation_digest,
409
                user_interpreter_constraints=user_interpreter_constraints,
410
                interpreter_universe=interpreter_universe,
411
                user_requirements=user_requirements,
412
                manylinux=manylinux,
413
                requirement_constraints=requirement_constraints,
414
                only_binary=only_binary,
415
                no_binary=no_binary,
416
                excludes=excludes,
417
                overrides=overrides,
418
                sources=sources,
419
                lock_style=lock_style,
420
                complete_platforms=complete_platforms,
421
            )
422
            .failure_reasons
423
        )
424

425
        if self.excludes != set(excludes):
1✔
426
            failure_reasons.add(InvalidPythonLockfileReason.EXCLUDES_MISMATCH)
1✔
427
        if self.overrides != set(overrides):
1✔
428
            failure_reasons.add(InvalidPythonLockfileReason.OVERRIDES_MISMATCH)
1✔
429

430
        return LockfileMetadataValidation(failure_reasons)
1✔
431

432

433
@_python_lockfile_metadata(5)
12✔
434
@dataclass(frozen=True)
12✔
435
class PythonLockfileMetadataV5(PythonLockfileMetadataV4):
12✔
436
    """Lockfile version with sources."""
437

438
    sources: set[str]
12✔
439

440
    @classmethod
12✔
441
    def _from_json_dict(
12✔
442
        cls: type[PythonLockfileMetadataV5],
443
        json_dict: dict[Any, Any],
444
        lockfile_description: str,
445
        error_suffix: str,
446
    ) -> PythonLockfileMetadataV5:
447
        v4_metadata = PythonLockfileMetadataV4._from_json_dict(
1✔
448
            json_dict, lockfile_description, error_suffix
449
        )
450
        metadata = _get_metadata(json_dict, lockfile_description, error_suffix)
1✔
451

452
        sources = metadata("sources", set[str], lambda l: set(l))
1✔
453

454
        return PythonLockfileMetadataV5(
1✔
455
            valid_for_interpreter_constraints=v4_metadata.valid_for_interpreter_constraints,
456
            requirements=v4_metadata.requirements,
457
            manylinux=v4_metadata.manylinux,
458
            requirement_constraints=v4_metadata.requirement_constraints,
459
            only_binary=v4_metadata.only_binary,
460
            no_binary=v4_metadata.no_binary,
461
            excludes=v4_metadata.excludes,
462
            overrides=v4_metadata.overrides,
463
            sources=sources,
464
        )
465

466
    @classmethod
12✔
467
    def additional_header_attrs(cls, instance: LockfileMetadata) -> dict[Any, Any]:
12✔
468
        instance = cast(PythonLockfileMetadataV5, instance)
2✔
469
        return {
2✔
470
            "sources": sorted(instance.sources),
471
        }
472

473
    def is_valid_for(
12✔
474
        self,
475
        *,
476
        expected_invalidation_digest: str | None,
477
        user_interpreter_constraints: InterpreterConstraints,
478
        interpreter_universe: Iterable[str],
479
        user_requirements: Iterable[PipRequirement],
480
        manylinux: str | None,
481
        requirement_constraints: Iterable[PipRequirement],
482
        only_binary: Iterable[str],
483
        no_binary: Iterable[str],
484
        excludes: Iterable[str],
485
        overrides: Iterable[str],
486
        sources: Iterable[str],
487
        lock_style: str | None,
488
        complete_platforms: Iterable[str],
489
    ) -> LockfileMetadataValidation:
490
        failure_reasons = (
1✔
491
            super()
492
            .is_valid_for(
493
                expected_invalidation_digest=expected_invalidation_digest,
494
                user_interpreter_constraints=user_interpreter_constraints,
495
                interpreter_universe=interpreter_universe,
496
                user_requirements=user_requirements,
497
                manylinux=manylinux,
498
                requirement_constraints=requirement_constraints,
499
                only_binary=only_binary,
500
                no_binary=no_binary,
501
                excludes=excludes,
502
                overrides=overrides,
503
                sources=sources,
504
                lock_style=lock_style,
505
                complete_platforms=complete_platforms,
506
            )
507
            .failure_reasons
508
        )
509

510
        if self.sources != set(sources):
1✔
511
            failure_reasons.add(InvalidPythonLockfileReason.SOURCES_MISMATCH)
1✔
512

513
        return LockfileMetadataValidation(failure_reasons)
1✔
514

515

516
@_python_lockfile_metadata(6)
12✔
517
@dataclass(frozen=True)
12✔
518
class PythonLockfileMetadataV6(PythonLockfileMetadataV5):
12✔
519
    """Lockfile version with lock_style and complete_platforms."""
520

521
    lock_style: str | None
12✔
522
    complete_platforms: Iterable[str]
12✔
523

524
    @classmethod
12✔
525
    def _from_json_dict(
12✔
526
        cls: type[PythonLockfileMetadataV6],
527
        json_dict: dict[Any, Any],
528
        lockfile_description: str,
529
        error_suffix: str,
530
    ) -> PythonLockfileMetadataV6:
531
        v5_metadata = PythonLockfileMetadataV5._from_json_dict(
1✔
532
            json_dict, lockfile_description, error_suffix
533
        )
534
        metadata = _get_metadata(json_dict, lockfile_description, error_suffix)
1✔
535

536
        lock_style = metadata("lock_style", str, lambda l: l)
1✔
537
        complete_platforms = metadata("complete_platforms", tuple[str, ...], lambda l: tuple(l))
1✔
538

539
        return PythonLockfileMetadataV6(
1✔
540
            valid_for_interpreter_constraints=v5_metadata.valid_for_interpreter_constraints,
541
            requirements=v5_metadata.requirements,
542
            manylinux=v5_metadata.manylinux,
543
            requirement_constraints=v5_metadata.requirement_constraints,
544
            only_binary=v5_metadata.only_binary,
545
            no_binary=v5_metadata.no_binary,
546
            excludes=v5_metadata.excludes,
547
            overrides=v5_metadata.overrides,
548
            sources=v5_metadata.sources,
549
            lock_style=lock_style,
550
            complete_platforms=complete_platforms,
551
        )
552

553
    @classmethod
12✔
554
    def additional_header_attrs(cls, instance: LockfileMetadata) -> dict[Any, Any]:
12✔
555
        instance = cast(PythonLockfileMetadataV6, instance)
2✔
556
        return {
2✔
557
            "lock_style": instance.lock_style,
558
            "complete_platforms": sorted(instance.complete_platforms),
559
        }
560

561
    def is_valid_for(
12✔
562
        self,
563
        *,
564
        expected_invalidation_digest: str | None,
565
        user_interpreter_constraints: InterpreterConstraints,
566
        interpreter_universe: Iterable[str],
567
        user_requirements: Iterable[PipRequirement],
568
        manylinux: str | None,
569
        requirement_constraints: Iterable[PipRequirement],
570
        only_binary: Iterable[str],
571
        no_binary: Iterable[str],
572
        excludes: Iterable[str],
573
        overrides: Iterable[str],
574
        sources: Iterable[str],
575
        lock_style: str | None,
576
        complete_platforms: Iterable[str],
577
    ) -> LockfileMetadataValidation:
UNCOV
578
        failure_reasons = (
×
579
            super()
580
            .is_valid_for(
581
                expected_invalidation_digest=expected_invalidation_digest,
582
                user_interpreter_constraints=user_interpreter_constraints,
583
                interpreter_universe=interpreter_universe,
584
                user_requirements=user_requirements,
585
                manylinux=manylinux,
586
                requirement_constraints=requirement_constraints,
587
                only_binary=only_binary,
588
                no_binary=no_binary,
589
                excludes=excludes,
590
                overrides=overrides,
591
                sources=sources,
592
                lock_style=lock_style,
593
                complete_platforms=complete_platforms,
594
            )
595
            .failure_reasons
596
        )
597

UNCOV
598
        if self.lock_style != lock_style:
×
UNCOV
599
            failure_reasons.add(InvalidPythonLockfileReason.LOCK_STYLE_MISMATCH)
×
UNCOV
600
        if self.complete_platforms != complete_platforms:
×
UNCOV
601
            failure_reasons.add(InvalidPythonLockfileReason.COMPLETE_PLATFORMS_MISMATCH)
×
602

UNCOV
603
        return LockfileMetadataValidation(failure_reasons)
×
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