Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/manpage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,9 @@ Options controlling ReFrame execution
- Sequence types: ``-S seqvar=1,2,3,4``
- Mapping types: ``-S mapvar=a:1,b:2,c:3``

Nested mapping types can also be converted using JSON syntax.
For example, the :attr:`~reframe.core.pipeline.RegressionTest.extra_resources` complex dictionary could be set with ``-S extra_resources='{"gpu": {"num_gpus_per_node":8}}'``.

Conversions to arbitrary objects are also supported.
See :class:`~reframe.utility.typecheck.ConvertibleType` for more details.

Expand Down Expand Up @@ -705,6 +708,9 @@ Options controlling ReFrame execution

Allow setting variables in fixtures.

.. versionchanged:: 4.4

Allow setting nested mapping types using JSON syntax.

.. option:: --skip-performance-check

Expand Down
31 changes: 18 additions & 13 deletions reframe/utility/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@

import abc
import datetime
import json
import re


Expand Down Expand Up @@ -322,19 +323,23 @@ def __rfm_cast_str__(cls, s):
mappping_type = cls._type
key_type = cls._key_type
value_type = cls._value_type
seq = []
for key_datum in s.split(','):
try:
k, v = key_datum.split(':')
except ValueError:
# Re-raise as TypeError
raise TypeError(
f'cannot convert string {s!r} to {cls.__name__!r}'
) from None

seq.append((key_type(k), value_type(v)))

return mappping_type(seq)

try:
items = json.loads(s)
except json.JSONDecodeError:
items = []
for key_datum in s.split(','):
try:
k, v = key_datum.split(':')
except ValueError:
# Re-raise as TypeError
raise TypeError(
f'cannot convert string {s!r} to {cls.__name__!r}'
) from None

items.append((key_type(k), value_type(v)))

return mappping_type(items)


class _StrType(_SequenceType):
Expand Down
8 changes: 8 additions & 0 deletions unittests/test_typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ def test_mapping_type():
# Test conversions
assert typ.Dict[str, int]('a:1,b:2') == {'a': 1, 'b': 2}

# Conversion with JSON syntax, for nested dictionaries
s = '{"gpu":{"num_gpus_per_node": 8}, "mpi": {"num_slots": 64}}'
expected = {
'gpu': {'num_gpus_per_node': 8},
'mpi': {'num_slots': 64},
}
assert typ.Dict[str, typ.Dict[str, object]](s) == expected

with pytest.raises(TypeError):
typ.Dict[str, int]('a:1,b')

Expand Down