Skip to content

Commit

Permalink
Add support for new operators &, + and - on spec arguments
Browse files Browse the repository at this point in the history
The self.args attribute on spec instances now support the &, + and -
operator to easily get a subset of keys or filter-out some keys.
The operations make specification of dependencies in specs easier
to read.

See it/e3-core#12
  • Loading branch information
Nikokrock committed Aug 19, 2024
1 parent cf5cfb4 commit 38f4efe
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
39 changes: 39 additions & 0 deletions src/e3/anod/qualifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Iterable


class Qualifier(dict):

def __sub__(self, other: Iterable[str]) -> Qualifier:
"""Create a new dict qualifier with some keys filtered-out.
Examples:
{"k1": "v1", "k2": "v2"} - {"k2"} == {"k1": "v1"}
{"k1": "v1", "k2": "v2"} - {"k2": "v3"} == {"k1": "v1"}
"""
return Qualifier({k: v for k, v in self.items() if k not in other})

def __add__(self, other: dict | None) -> Qualifier:
"""Create a new dict qualifier that merges two dicts.
The operation is equivalent to pipe operator with the difference that
its priority is higher as defined by Python standard. This allows more
natural expression that mix + and - operators (both operators have the
same priority).
"""
if other is None:
return Qualifier(self)
else:
return Qualifier(self | other)

def __and__(self, other: Iterable[str]) -> Qualifier:
"""Create a new dict qualifier with the subset other of the keys.
Examples:
{"k1": "v1", "k2": "v2"} & {"k2"} == {"k2": "v2"}
{"k1": "v1", "k2": "v2"} & {"k2": "v3"} == {"k2": "v2"}
"""
return Qualifier({k: v for k, v in self.items() if k in other})
3 changes: 2 additions & 1 deletion src/e3/anod/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from e3.anod.error import AnodError, ShellError
from e3.anod import qualifier_dict_to_str, qualifier_str_to_dict
from e3.anod.qualifiers_manager import QualifiersManager
from e3.anod.qualifier import Qualifier
from e3.fs import find
from e3.os.fs import which
from e3.platform_db.knowledge_base import OS_INFO
Expand Down Expand Up @@ -353,7 +354,7 @@ def declare_qualifiers_and_components(
def args(self) -> dict[str, str | bool | frozenset[str]]:
"""Access to final qualifier values (with defaults set)."""
if self.enable_name_generator:
return self.qualifiers_manager.qualifier_values
return Qualifier(self.qualifiers_manager.qualifier_values)
else:
return self.parsed_qualifier # type: ignore

Expand Down
27 changes: 27 additions & 0 deletions tests/tests_e3/anod/test_qualifier_manager.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from e3.anod.error import AnodError
from e3.anod.qualifier import Qualifier
from e3.anod.qualifiers_manager import (
QualifiersManager,
KeyValueDeclaration,
Expand All @@ -10,6 +11,32 @@
import pytest


def test_qualifier_operations():
qual1 = Qualifier({"key1": "v1", "key2": "v2"})
qual2 = Qualifier({"key2": "v2.2", "key3": "v3"})
qual3 = Qualifier({"key1": "v1.3", "key4": "v4"})

# Test basic addition of qualifiers
assert qual1 + qual2 == Qualifier({"key1": "v1", "key2": "v2.2", "key3": "v3"})

# Test basic filtering-out of keys
assert qual1 - qual2 == Qualifier({"key1": "v1"})
assert qual1 - {"key2"} == Qualifier({"key1": "v1"})

# Test order/priority of operators
# + and - have the same priority thus are evaluated from left to right
assert qual1 + qual2 - qual3 == Qualifier({"key2": "v2.2", "key3": "v3"})
assert qual1 + (qual2 - qual3) == Qualifier(
{"key1": "v1", "key2": "v2.2", "key3": "v3"}
)

# & has a lower priority than +
assert qual1 + qual2 + qual3 & {"key1", "key2"} == Qualifier(
{"key1": "v1.3", "key2": "v2.2"}
)
assert (qual1 + None) == qual1


# Cover Anod (e3.anod.spec.py)
def test_anod_name_generator():
# Create a dummy spec.
Expand Down

0 comments on commit 38f4efe

Please sign in to comment.