Skip to content

Commit

Permalink
Coerce dimensionless values of SizeConstraint to values with dimensio…
Browse files Browse the repository at this point in the history
…ns (#3076)
  • Loading branch information
skycastlelily authored Jul 22, 2024
1 parent b81c362 commit 5e6db4b
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
20 changes: 20 additions & 0 deletions tests/unit/test_hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ def test_constraint_name_pattern(value: str, expected: tuple[Any, Any]) -> None:
assert match.groups() == expected


_size_constraint_pattern_input = [
({'name': 'num_with_default', 'raw_value': '10', 'default_unit': 'GiB'},
'num_with_default: == 10 gibibyte'),
({'name': 'num_without_default', 'raw_value': '1024'}, 'num_without_default: == 1024 byte'),
({'name': 'num_with_unit', 'raw_value': '10 GiB', 'default_unit': 'MiB'},
'num_with_unit: == 10 GiB'),
]


@pytest.mark.parametrize(
('value', 'expected'),
_size_constraint_pattern_input,
)
def test_constraint_default_unit(value: dict, expected: tuple[Any, Any]) -> None:
constraint_out = tmt.hardware.SizeConstraint.from_specification(**value)

assert constraint_out is not None
assert str(constraint_out) == expected


_constraint_components_pattern_input = [
('memory 10 GiB', ('memory', None, None, None, '10 GiB')),
('cpu.processors != 4 ', ('cpu', None, 'processors', '!=', '4')),
Expand Down
14 changes: 9 additions & 5 deletions tmt/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ class Constraint(BaseConstraint, Generic[ConstraintValueT]):
raw_value: str

# If set, it is a raw unit specified by the constraint.
unit: Optional[str] = None
default_unit: Optional[str] = None

# If set, it is a "bigger" constraint, to which this constraint logically
# belongs as one of its aspects.
Expand All @@ -507,7 +507,8 @@ def _from_specification(
as_quantity: bool = True,
as_cast: Optional[Callable[[str], ConstraintValueT]] = None,
original_constraint: Optional['Constraint[Any]'] = None,
allowed_operators: Optional[list[Operator]] = None
allowed_operators: Optional[list[Operator]] = None,
default_unit: Optional[Any] = "bytes"
) -> T:
"""
Parse raw constraint specification into our internal representation.
Expand All @@ -520,6 +521,7 @@ def _from_specification(
:param original_constraint: when specified, new constraint logically belongs to
``original_constraint``, possibly representing one of its aspects.
:param allowed_operators: if specified, only operators on this list are accepted.
:param default_unit: if raw_value contains no unit, this unit will be appended.
:raises ParseError: when parsing fails, or the operator is now allowed.
:returns: a :py:class:`Constraint` representing the given specification.
"""
Expand Down Expand Up @@ -560,7 +562,7 @@ def _from_specification(
if not isinstance(
value,
pint.Quantity): # type: ignore[reportUnnecessaryIsInstance,unused-ignore]
value = pint.Quantity(value)
value = pint.Quantity(value, default_unit)

elif as_cast is not None:
value = as_cast(raw_value)
Expand Down Expand Up @@ -672,14 +674,16 @@ def from_specification(
name: str,
raw_value: str,
original_constraint: Optional['Constraint[Any]'] = None,
allowed_operators: Optional[list[Operator]] = None
allowed_operators: Optional[list[Operator]] = None,
default_unit: Optional[Any] = 'bytes'
) -> T:
return cls._from_specification(
name,
raw_value,
as_quantity=True,
original_constraint=original_constraint,
allowed_operators=allowed_operators
allowed_operators=allowed_operators,
default_unit=default_unit
)


Expand Down

0 comments on commit 5e6db4b

Please sign in to comment.