Skip to content

Commit

Permalink
Merge 14ec7ad into bfd65d8
Browse files Browse the repository at this point in the history
  • Loading branch information
jsirois committed Sep 15, 2020
2 parents bfd65d8 + 14ec7ad commit d7112b3
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
39 changes: 30 additions & 9 deletions src/python/pants/engine/internals/uuid.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,49 @@
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

import random
import uuid
from dataclasses import dataclass, field
from dataclasses import dataclass
from enum import Enum
from typing import Optional, cast

from pants.engine.rules import _uncacheable_rule, collect_rules
from pants.engine.rules import collect_rules, rule
from pants.util.meta import frozen_after_init


@dataclass(frozen=True)
class UUIDScope(Enum):
PER_CALL = "call"
PER_SESSION = "session"


@frozen_after_init
@dataclass(unsafe_hash=True)
class UUIDRequest:
randomizer: float = field(default_factory=random.random)
scope: str

def __init__(self, scope: Optional[str] = None) -> None:
self.scope = scope if scope is not None else self._to_scope_name(UUIDScope.PER_CALL)

@staticmethod
def _to_scope_name(scope: UUIDScope) -> str:
if scope == UUIDScope.PER_CALL:
return uuid.uuid4().hex
return cast(str, scope.value)

@classmethod
def scoped(cls, scope: UUIDScope) -> "UUIDRequest":
return cls(cls._to_scope_name(scope))


@_uncacheable_rule
@rule
async def generate_uuid(_: UUIDRequest) -> uuid.UUID:
"""A rule to generate a UUID.
Useful primarily to force a rule to re-run: a rule that `await Get`s on a UUIDRequest will be
uncacheable, because this rule is itself uncacheable.
Note that this will return a new UUID each time if request multiple times in a single session.
If you want two requests to return the same UUID, set the `randomizer` field in both
requests to some fixed value.
Note that this will return a new UUID each time if requested multiple times in a single session.
If you want two requests to return the same UUID, set the `scope` field in both requests to some
fixed scope value.
"""
return uuid.uuid4()

Expand Down
30 changes: 25 additions & 5 deletions src/python/pants/engine/internals/uuid_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from pants.engine.internals.uuid import UUIDRequest
from pants.engine.internals.uuid import UUIDRequest, UUIDScope
from pants.engine.internals.uuid import rules as uuid_rules
from pants.engine.rules import QueryRule
from pants.testutil.rule_runner import RuleRunner
Expand All @@ -16,13 +16,33 @@ def rule_runner() -> RuleRunner:
return RuleRunner(rules=[*uuid_rules(), QueryRule(UUID, (UUIDRequest,))])


def test_distinct_uuids(rule_runner: RuleRunner) -> None:
def test_distinct_uuids_default_scope(rule_runner: RuleRunner) -> None:
uuid1 = rule_runner.request_product(UUID, [UUIDRequest()])
uuid2 = rule_runner.request_product(UUID, [UUIDRequest()])
assert uuid1 != uuid2


def test_identical_uuids(rule_runner: RuleRunner) -> None:
uuid1 = rule_runner.request_product(UUID, [UUIDRequest(randomizer=0.0)])
uuid2 = rule_runner.request_product(UUID, [UUIDRequest(randomizer=0.0)])
def test_distinct_uuids_different_scopes(rule_runner: RuleRunner) -> None:
uuid1 = rule_runner.request_product(UUID, [UUIDRequest(scope="this")])
uuid2 = rule_runner.request_product(UUID, [UUIDRequest(scope="that")])
assert uuid1 != uuid2


def test_identical_uuids_same_scope(rule_runner: RuleRunner) -> None:
uuid1 = rule_runner.request_product(UUID, [UUIDRequest(scope="this")])
uuid2 = rule_runner.request_product(UUID, [UUIDRequest(scope="this")])
assert uuid1 == uuid2


def test_distinct_uuids_call_scope(rule_runner: RuleRunner) -> None:
uuid1 = rule_runner.request_product(UUID, [UUIDRequest()])
uuid2 = rule_runner.request_product(UUID, [UUIDRequest(scope="bob")])
uuid3 = rule_runner.request_product(UUID, [UUIDRequest.scoped(UUIDScope.PER_CALL)])
uuid4 = rule_runner.request_product(UUID, [UUIDRequest.scoped(UUIDScope.PER_CALL)])
assert uuid1 != uuid2 != uuid3 != uuid4


def test_identical_uuids_session_scope(rule_runner: RuleRunner) -> None:
uuid1 = rule_runner.request_product(UUID, [UUIDRequest.scoped(UUIDScope.PER_SESSION)])
uuid2 = rule_runner.request_product(UUID, [UUIDRequest.scoped(UUIDScope.PER_SESSION)])
assert uuid1 == uuid2

0 comments on commit d7112b3

Please sign in to comment.