예제 #1
0
def _matches_field_values(
    handler: handlers.ResourceHandler,
    cause: causes.ResourceCause,
    kwargs: MutableMapping[str, Any],
) -> bool:
    if not handler.field:
        return True

    if not kwargs:
        kwargs.update(cause.kwargs)

    absent = _UNSET.token  # or any other identifyable object
    if isinstance(cause, causes.ChangingCause):
        # For on.update/on.field, so as for on.create/resume/delete for uniformity and simplicity:
        old = dicts.resolve(cause.old, handler.field, absent)
        new = dicts.resolve(cause.new, handler.field, absent)
        values = [
            new, old
        ]  # keep "new" first, to avoid "old" callbacks if "new" works.
    else:
        # For event-watching, timers/daemons (could also work for on.create/resume/delete):
        val = dicts.resolve(cause.body, handler.field, absent)
        values = [val]
    return ((handler.value is None and any(value is not absent
                                           for value in values))
            or (handler.value is filters.PRESENT and any(value is not absent
                                                         for value in values))
            or (handler.value is filters.ABSENT and any(value is absent
                                                        for value in values))
            or (callable(handler.value)
                and any(handler.value(value, **kwargs) for value in values))
            or (any(handler.value == value for value in values)))
예제 #2
0
def _matches_field_changes(
    handler: handlers.ResourceHandler,
    cause: causes.ResourceCause,
    kwargs: MutableMapping[str, Any],
) -> bool:
    if not isinstance(handler, handlers.ChangingHandler):
        return True
    if not isinstance(cause, causes.ChangingCause):
        return True
    if not handler.field:
        return True

    if not kwargs:
        kwargs.update(cause.kwargs)

    absent = _UNSET.token  # or any other identifyable object
    old = dicts.resolve(cause.old, handler.field, absent)
    new = dicts.resolve(cause.new, handler.field, absent)
    return ((
        not handler.field_needs_change
        or old != new  # ... or there IS a change.
    ) and ((handler.old is None) or
           (handler.old is filters.ABSENT and old is absent) or
           (handler.old is filters.PRESENT and old is not absent) or
           (callable(handler.old) and handler.old(old, **kwargs)) or
           (handler.old == old))
            and ((handler.new is None) or
                 (handler.new is filters.ABSENT and new is absent) or
                 (handler.new is filters.PRESENT and new is not absent) or
                 (callable(handler.new) and handler.new(new, **kwargs)) or
                 (handler.new == new)))
예제 #3
0
 def adjust_cause(self, cause: execution.CauseT) -> execution.CauseT:
     if self.field is not None and isinstance(cause, causes.ChangingCause):
         old = dicts.resolve(cause.old, self.field, None)
         new = dicts.resolve(cause.new, self.field, None)
         diff = diffs.reduce(cause.diff, self.field)
         new_cause = dataclasses.replace(cause, old=old, new=new, diff=diff)
         return cast(execution.CauseT, new_cause)  # TODO: mypy bug?
     else:
         return cause
예제 #4
0
 def purge(
     self,
     *,
     key: ids.HandlerId,
     body: bodies.Body,
     patch: patches.Patch,
 ) -> None:
     absent = object()
     key_field = self.field + (key, )
     body_value = dicts.resolve(body, key_field, absent)
     patch_value = dicts.resolve(patch, key_field, absent)
     if body_value is not absent:
         dicts.ensure(patch, key_field, None)
     elif patch_value is not absent:
         dicts.remove(patch, key_field)
예제 #5
0
 def purge(
     self,
     *,
     key: ids.HandlerId,
     body: bodies.Body,
     patch: patches.Patch,
 ) -> None:
     absent = object()
     for full_key in self.make_keys(key, body=body):
         key_field = ['metadata', 'annotations', full_key]
         body_value = dicts.resolve(body, key_field, absent)
         patch_value = dicts.resolve(patch, key_field, absent)
         if body_value is not absent:
             dicts.ensure(patch, key_field, None)
         elif patch_value is not absent:
             dicts.remove(patch, key_field)
예제 #6
0
 def fetch(
     self,
     *,
     body: bodies.Body,
 ) -> Optional[bodies.BodyEssence]:
     encoded: Optional[str] = dicts.resolve(body, self.field, None)
     essence: Optional[bodies.BodyEssence] = json.loads(
         encoded) if encoded is not None else None
     return essence
예제 #7
0
 def fetch(
     self,
     *,
     key: ids.HandlerId,
     body: bodies.Body,
 ) -> Optional[ProgressRecord]:
     container: Mapping[ids.HandlerId, ProgressRecord]
     container = dicts.resolve(body, self.field, {})
     return container.get(key, None)
예제 #8
0
 def touch(
     self,
     *,
     body: bodies.Body,
     patch: patches.Patch,
     value: Optional[str],
 ) -> None:
     key_field = self.touch_field
     body_value = dicts.resolve(body, key_field, None)
     if body_value != value:  # also covers absent-vs-None cases.
         dicts.ensure(patch, key_field, value)
예제 #9
0
def reduce_iter(
    d: Diff,
    path: dicts.FieldPath,
) -> Iterator[DiffItem]:
    for op, field, old, new in d:

        # As-is diff (i.e. a root field).
        if not path:
            yield DiffItem(op, tuple(field), old, new)

        # The diff-field is longer than the path: get "spec.struct" when "spec.struct.field" is set.
        # Retranslate the diff with the field prefix shrinked.
        elif tuple(field[:len(path)]) == tuple(path):
            yield DiffItem(op, tuple(field[len(path):]), old, new)

        # The diff-field is shorter than the path: get "spec.struct" when "spec={...}" is added.
        # Generate a new diff, with new ops, for the resolved sub-field.
        elif tuple(field) == tuple(path[:len(field)]):
            tail = path[len(field):]
            old_tail = dicts.resolve(old, tail, default=None)
            new_tail = dicts.resolve(new, tail, default=None)
            yield from diff_iter(old_tail, new_tail)
예제 #10
0
 def fetch(
     self,
     *,
     key: ids.HandlerId,
     body: bodies.Body,
 ) -> Optional[ProgressRecord]:
     for full_key in self.make_keys(key, body=body):
         key_field = ['metadata', 'annotations', full_key]
         encoded = dicts.resolve(body, key_field, None)
         decoded = json.loads(encoded) if encoded is not None else None
         if decoded is not None:
             return cast(ProgressRecord, decoded)
     return None
예제 #11
0
 def touch(
     self,
     *,
     body: bodies.Body,
     patch: patches.Patch,
     value: Optional[str],
 ) -> None:
     for full_key in self.make_keys(self.touch_key, body=body):
         key_field = ['metadata', 'annotations', full_key]
         body_value = dicts.resolve(body, key_field, None)
         if body_value != value:  # also covers absent-vs-None cases.
             dicts.ensure(patch, key_field, value)
             self._store_marker(prefix=self.prefix, patch=patch, body=body)
예제 #12
0
def test_dict_with_empty_path(resolve):
    d = {'key': 'val'}
    r = resolve(d, [])
    assert r == d
    assert r is d
예제 #13
0
def test_dict_with_none_is_treated_as_a_regular_default_value(resolve):
    d = {'abc': {'def': {'hij': 'val'}}}
    r = resolve(d, ['abc', 'def', 'xyz'], None)
    assert r is None
예제 #14
0
def test_dict_with_nonmapping_with_default(resolve):
    d = {'key': 'val'}
    r = resolve(d, ['key', 'sub'], default)
    assert r is default
예제 #15
0
def test_dict_with_nonmapping_with_no_default(resolve):
    d = {'key': 'val'}
    with pytest.raises(TypeError):
        resolve(d, ['key', 'sub'])
예제 #16
0
def test_dict_with_inexistent_key_with_default(resolve, key):
    d = {'abc': {'def': {'hij': 'val'}}}
    r = resolve(d, key, default)
    assert r is default
예제 #17
0
def test_dict_with_inexistent_key_with_no_default(resolve, key):
    d = {'abc': {'def': {'hij': 'val'}}}
    with pytest.raises(KeyError):
        resolve(d, key)
예제 #18
0
def test_dict_with_existent_key_with_default(resolve):
    d = {'abc': {'def': {'hij': 'val'}}}
    r = resolve(d, ['abc', 'def', 'hij'], default)
    assert r == 'val'