Skip to content

[feat] Add support for combining system:partition and features/extras in valid_systems#3613

Open
casparvl wants to merge 2 commits intoreframe-hpc:developfrom
casparvl:support_combining_syspart_features_valid_systems
Open

[feat] Add support for combining system:partition and features/extras in valid_systems#3613
casparvl wants to merge 2 commits intoreframe-hpc:developfrom
casparvl:support_combining_syspart_features_valid_systems

Conversation

@casparvl
Copy link

This was requested in #2820 , although that was eventually closed with a suggestion for a workaround.

However, I hit it again when trying to use reframe.utils.find_modules(substr, ...) in combination with wanting to specify additional features. Example use cases (and there's many more one can come up with):

  • I may have a software X for which want to not run CPU tests on a GPU node. I normally achieve that by assigning the CPU feature to my CPU partitions (but not to my GPU partitions) and then requesting the CPU feature from my CPU-only tests.
  • I may have two variants of a bandwidth test (which needs module Y): one sending small packets, one sending larger packets. I only want to run larger one only on partitions that have the infiniband feature.

In both cases, we want to test all modules with X or Y respectively that are available on our system, hence we want to use the find_modules function. However, the first element of the tuple this returns is the system:partition string for which it found the module matching the requested substring. This is clearly meant to be used in valid_systems directly (as is confirmed by the example in the docs), but for the examples above, you may want to only run on a subset of these system:partition combinations (based on the required features. It would be very natural to then do:

module_info = parameter(find_modules('X'))
...
self.valid_systems - [module_info[0] + ' +feat1']

To make sure that a partition is only valid if it provides the right module and the right feature.

It turned out that the code changes needed are very limited (it seems like a lot because the indentation changed, but the key part is:

  • not splitting the system:partition case from the feature/extra specification case
  • Handling the system:partition case with an extra elif on the subspec:
            elif ':' in subspec and not subspec.startswith(('+', '-', '%')):
                # If there is a system:partition specified, make sure it
                # matches one of the items in valid_matches
                syspart_match = True if subspec in valid_matches else False

And adding that syspart_match to the return logic:

        # If the partition has all the plus features, none of the minus
        # all of the properties and the system:partition spec (if any)
        # matched, this partition is valid
        if (
            have_plus_feats and not have_minus_feats and have_props
            and syspart_match
        ):
            return True

Note that this logic does not assume the system:partition to strictly come before or after the features/extras, so I've adapted the valid syntax specification to allow both:

_VALID_SYS_SYNTAX = rf'^(({_FKV}\s+)*{_S}(\s+{_FKV})*|{_FKV}(\s+{_FKV})*)$'

If anything, I feel the code has become cleaner by not handling system:partition as a special, separate case, but as 'just another item' that may occur as a subspec.

@codecov
Copy link

codecov bot commented Jan 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.37%. Comparing base (da2fbb3) to head (89259dd).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #3613   +/-   ##
========================================
  Coverage    91.37%   91.37%           
========================================
  Files           62       62           
  Lines        13484    13484           
========================================
  Hits         12321    12321           
  Misses        1163     1163           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@casparvl
Copy link
Author

casparvl commented Jan 21, 2026

I've done some concrete testing to prove this works. Note that I have 4 partitions (rome, genoa, gpu_A100, gpu_H100), of which the first two have the cpu feature assigned. Each partition has two environments: EESSI-2023.06 and EESSI-2025.06.

**Case 1: traditional `system:partition` assignment**
module_info = parameter(find_modules('SciPy-bundle'))
...
        s, e, m = self.module_info
        self.valid_systems = [s]

Output:

[       OK ] (1/8) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') /586a9dfe @snellius:rome+EESSI-2023.06
...
[       OK ] (2/8) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') /fe4be974 @snellius:rome+EESSI-2025.06
...
[       OK ] (3/8) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') /93bc1dc5 @snellius:genoa+EESSI-2023.06
...
[       OK ] (4/8) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') /3034e72c @snellius:genoa+EESSI-2025.06
...
[       OK ] (5/8) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') /80754277 @snellius:gpu_A100+EESSI-2023.06
...
[       OK ] (6/8) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') /8f6a7e95 @snellius:gpu_A100+EESSI-2025.06
...
[       OK ] (7/8) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') /e6d136b9 @snellius:gpu_H100+EESSI-2023.06
...
[       OK ] (8/8) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') /bf9cd015 @snellius:gpu_H100+EESSI-2025.06
...
[----------] all spawned checks have finished
**Case 2: Combining system:partition with +feat1**
module_info = parameter(find_modules('SciPy-bundle'))
...
        s, e, m = self.module_info
        self.valid_systems = [s + ' +cpu']

Output:

[       OK ] (1/4) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /586a9dfe @snellius:rome+EESSI-2023.06
...
[       OK ] (2/4) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /fe4be974 @snellius:rome+EESSI-2025.06
...
[       OK ] (3/4) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /93bc1dc5 @snellius:genoa+EESSI-2023.06
...
[       OK ] (4/4) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /3034e72c @snellius:genoa+EESSI-2025.06
...
[----------] all spawned checks have finished
**Case 3: Combining system:partition with -feat1**
module_info = parameter(find_modules('SciPy-bundle'))
...
        s, e, m = self.module_info
        self.valid_systems = [s + ' +cpu']

Output:

[       OK ] (1/4) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /80754277 @snellius:gpu_A100+EESSI-2023.06
...
[       OK ] (2/4) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /8f6a7e95 @snellius:gpu_A100+EESSI-2025.06
...
[       OK ] (3/4) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /e6d136b9 @snellius:gpu_H100+EESSI-2023.06
...
[       OK ] (4/4) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /bf9cd015 @snellius:gpu_H100+EESSI-2025.06
...
[----------] all spawned checks have finished
**Case 4: Using only features**

This case clearly doesn't make any sense, because it'll create tests where the first element of module_info is X and then the partition that will be used is Y, but just to prove that a valid_systems with only features still works:

module_info = parameter(find_modules('SciPy-bundle'))
...
        s, e, m = self.module_info
        self.valid_systems = ['+cpu']

Output:

[       OK ] ( 1/16) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /586a9dfe @snellius:rome+EESSI-2023.06
...
[       OK ] ( 2/16) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /586a9dfe @snellius:genoa+EESSI-2023.06
...
[       OK ] ( 3/16) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /fe4be974 @snellius:rome+EESSI-2025.06
...
[       OK ] ( 4/16) EESSI_ModuleFinder2 %module_info=('snellius:rome', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /fe4be974 @snellius:genoa+EESSI-2025.06
...
[       OK ] ( 5/16) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /93bc1dc5 @snellius:rome+EESSI-2023.06
...
[       OK ] ( 6/16) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /93bc1dc5 @snellius:genoa+EESSI-2023.06
...
[       OK ] ( 7/16) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /3034e72c @snellius:rome+EESSI-2025.06
...
[       OK ] ( 8/16) EESSI_ModuleFinder2 %module_info=('snellius:genoa', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /3034e72c @snellius:genoa+EESSI-2025.06
...
[       OK ] ( 9/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /80754277 @snellius:rome+EESSI-2023.06
...
[       OK ] (10/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /80754277 @snellius:genoa+EESSI-2023.06
...
[       OK ] (11/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /8f6a7e95 @snellius:rome+EESSI-2025.06
...
[       OK ] (12/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_A100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /8f6a7e95 @snellius:genoa+EESSI-2025.06
...
[       OK ] (13/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /e6d136b9 @snellius:rome+EESSI-2023.06
...
[       OK ] (14/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2023.06', 'SciPy-bundle/2023.11-gfbf-2023b') %scale=1_core /e6d136b9 @snellius:genoa+EESSI-2023.06
...
[       OK ] (15/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /bf9cd015 @snellius:rome+EESSI-2025.06
...
[       OK ] (16/16) EESSI_ModuleFinder2 %module_info=('snellius:gpu_H100', 'EESSI-2025.06', 'SciPy-bundle/2025.06-gfbf-2025a') %scale=1_core /bf9cd015 @snellius:genoa+EESSI-2025.06
...
[----------] all spawned checks have finished

@casparvl
Copy link
Author

Hm, I have to recheck how the current if...elif...elif handles sysname * and *:partname cases. My bet is, it handles them incorrectly.

@vkarak
Copy link
Contributor

vkarak commented Feb 26, 2026

@casparvl I see the problem you are facing, but I don't agree with the solution conceptually. Allowing a syntax like valid_systems = ['system:partition +foo'] is contradictory, because we ask for pinning to a specific system/partition combination, and then we actually don't mean it. I would see as valid this valid_systems = ['system +foo'], which it would essentially select all partitions with foo from system, but I think that's superfluous and equivalent to valid_systems = ['+foo'], since the system is given once the test is loaded.

The problem is more fundamental. It is the fact that find_modules() does not understand the features and extras. It should instead take the valid_systems as an argument and then return the system/partition combination that respects both the given constraints and provides the given module.

This pattern is not unique to find_modules() but to any user function that needs to parameterize over the system/partitions/environment combination, and I believe this must be made easier by the framework. Check also the discussion in #3323, which is related.

@casparvl
Copy link
Author

casparvl commented Mar 10, 2026

@vkarak Sorry for the slow response, I was on holiday.

Allowing a syntax like valid_systems = ['system:partition +foo'] is contradictory, because we ask for pinning to a specific system/partition combination, and then we actually don't mean it.

Hm, coming from the more traditional syntax before features/extras where a thing, I see your point. But your solution makes the pretty hard assumption that the valid_systems is known and fixed at the moment find_modules is called (typically in the class body, since you typically parameterize over the modules). That's not the case for us. For our particular case, some of our features get added to valid_systems as part of a run_after('init') hook. In fact: some depend on what find_modules returns (e.g. if a module contains -CUDA, we add a feature +gpu). That means that when find_modules is called (in the class body), the valid_systems doesn't have a final value yet.

In this context, having both a system:partition specification and a +feat specification is the easiest, most pragmatic way to get the right filtering - even if it may feel like an overspecified thing initially.

I'm not saying there aren't any other options: if we have access to configuration objects in the after-init hook (as discussed in #3323 ), I guess we could take the system:partition returned by find_modules, determine if that has the required +gpu feature, and if not just set valid_systems=[] or something (again: all in an after-init hook). In that case, we (at least for our particular use case) wouldn't even need a find_modules that is valid_systems-aware - we'd just fix it all based on what find_modules returns in terms of system-partition combinations.

But: such an approach does feel very clunky, as we're bypassing the whole feature mechanism. Compared to that, I'd find the system:partition +foo specification much more elegant.

@smoors
Copy link
Collaborator

smoors commented Mar 11, 2026

@casparvl I see the problem you are facing, but I don't agree with the solution conceptually. Allowing a syntax like valid_systems = ['system:partition +foo'] is contradictory, because we ask for pinning to a specific system/partition combination, and then we actually don't mean it.

to be blunt, i don't see what's contradictory here. valid_systems = ['system:partition +foo'] does not just ask for a specific system/partition combination, it only asks for that specific system/partition combination if it also has +foo.

i understand why it looks strange to you, but this PR solves our problem in a relatively simple and generic way. is there any technical reason why this can't be merged?

@casparvl
Copy link
Author

casparvl commented Mar 12, 2026

There's also valid_systems = ['system:* +foo'] and valid_systems = ['*:partition +foo'] which are currently invalid. This PR makes that valid syntax, and those are clearly not overspecified/contradictory: the first would simply mean "any partition on system that has feature foo", and the second "any system with a partition partition that also has feature foo" (on some systems partition might have foo, on others it might not - so this is not overspecified or contradictory).

@vkarak
Copy link
Contributor

vkarak commented Mar 12, 2026

Let's step back a bit from the solution and try to understand the problem. Could you please show me a concrete example of these two cases:

I may have a software X for which want to not run CPU tests on a GPU node. I normally achieve that by assigning the CPU feature to my CPU partitions (but not to my GPU partitions) and then requesting the CPU feature from my CPU-only tests.

I may have two variants of a bandwidth test (which needs module Y): one sending small packets, one sending larger packets. I only want to run larger one only on partitions that have the infiniband feature.

It doesn't have to be the full test. I need to see:

  1. All the places where valid_systems are set and how
  2. The return value of the find_modules() and how it is used to parameterise the test.

@vkarak
Copy link
Contributor

vkarak commented Mar 12, 2026

I checked the eessi-testsuite code and I believe I recognized the pattern in the issue description. I guess you want to replace your custom find_modules() with the one provided by reframe, right? If the software stack is uniform across all partitions, then you can simply ignore the partition, environment combination and just use the module name. This would make it equivalent to your find_modules(). The reason the documentation suggests pinning the system is because a module found in one partition may not be present in another one. Iiuc you use the module name to place constraints to the test post-init. This is not bad, except that you pay the cost of generating parameterizations that you will eventually not need, and this is a limitation of the framework. That's why I am saying that we are missing a more fundamental feature. Otherwise, switching to reframe's find_modules() but just using the module names, it should be completely equivalent to what you are doing right now.

@vkarak
Copy link
Contributor

vkarak commented Mar 13, 2026

After quite some thought I think I am now more positive for the ['system:part +foo'] syntax, because the test is allowed to add more constraints immediately after its initialization, before it is specialized for every partition/environment combination.

The pinning of the system is the only way I can think of currently to properly parameterize over a set of partition parameters. Imagine the following test:

class Test(...):
    valid_systems = ['+gpu']
    gpu = parameter(gpus_by_partition(valid_systems))
    config = parameter(['foo', 'bar'])

    @run_after('init')
    def set_more_constraints(self):
        constr = self.gpu[0]    # This gives the valid sys:part
        if self.config == 'foo':
            constr += ' +foo'

        self.valid_systems = [constr]

This test expresses its initial intent with valid_systems, that it needs a gpu. It passes this to the gpus_by_partition function, which will parameterize it over the number of gpus in every partition that has gpus. This returns the (sys:part, gpu_no) to inform the test about the partition this gpu_no refers to. However, it is still totally valid for a test to request an additional constraint based on its parameters, as it would be the case in any other type of parameterization that does not depend on system parameters. So under this rationale, I think the ['system:part +foo'] makes sense and practically means "run on system:part only if it has also the foo feature."

I am not convinced for the necessity of the other * syntaxes though.

On another note regarding system parameterization, I think the framework should provide a special type of parameter that will do the pinning of the system and environment transparently for such cases and avoid the ugly tuple-based parameterization. Also it should provide an easy way to extend a constraint. Ideally, this should be written as:

class Test(...):
    valid_systems = ['+gpu']
    gpu = system_parameter(gpus_by_partition(valid_systems))
    config = parameter(['foo', 'bar'])

    @run_after('init')
    def set_more_constraints(self):
        if self.config == 'foo':
            self.valid_systems @= ['+foo']

@casparvl
Copy link
Author

I guess you want to replace your custom find_modules() with the one provided by reframe, right?

Yes, though

If the software stack is uniform across all partitions, then you can simply ignore the partition, environment combination and just use the module name.

the reason for wanting to replace it is actually because we want to use ReFrame's concept of environment to discover modules across different versions of EESSI. And the available modules are different accross the different EESSI versions.

because the test is allowed to add more constraints immediately after its initialization, before it is specialized for every partition/environment combination

That's much better phrasing than I used, but that's indeed exactly what we are doing: adding constraint after initialization, but before specialization. In your example, you're basing the extra feature on a parameter value (if a certain parameter is foo, you add +foo). That's very similar to what we do: we parameterize over the available modules, and then base the additional feature on the name of the module (i.e. if the module contains -CUDA, we add +gpu). But the principle is exactly the same.

"run on system:part only if it has also the foo feature."

Exactly. I think that the ability to express something like this (and express it 'late', i.e. right before specialization, so that it can include parameter-based conditions) opens up interesting possibilities for people implementing tests in ReFrame.

I am not convinced for the necessity of the other * syntaxes though.

I don't personally care too much about the *-based syntaxes myself. Do you care enough that you'd to actively prevent combining * syntax with features/extras? I personally don't think we should: it'll make the code a more messy as

  • specifying the _VALID_SYS_SYNTAX will be a lot harder (can't simply reuse the _S as easily, I'll have to fully differentiate between a standalone sys:part case, and a sys:part +feat %extra case)
  • in my current PR, I can do a single check elif not subspec.startswith(('+', '-', '%')):, since it doesn't matter whether there is a system:partition syntax on its own, or together with a feature. If want to forbid * syntax from being combined with features/extras, I'd have to first loop through all subspecs to figure out if it is a stand-alone system:part specification, or whether it is combined with features - and then treat them differently.

Honestly, I don't think it's worth the extra trouble and code complexity - but let me know if you feel differently.

@vkarak vkarak added this to the ReFrame 4.10 milestone Mar 25, 2026
@vkarak vkarak changed the title Add support for combining system:partition and features/extras in valid_systems [feat] Add support for combining system:partition and features/extras in valid_systems Mar 25, 2026
Copy link
Contributor

@vkarak vkarak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made some suggestions for improving this PR based on our the discussion. Some are aesthetic. We will also need to update the docs.


_S = rf'({_NW}(:{_NW})?)' # system/partition
_VALID_SYS_SYNTAX = rf'^({_S}|{_FKV}(\s+{_FKV})*)$'
_VALID_SYS_SYNTAX = rf'^(({_FKV}\s+)*{_S}(\s+{_FKV})*|{_FKV}(\s+{_FKV})*)$'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrite as such to make it clearer. This version does not accept the wildcard syntaxes with the features:

Suggested change
_VALID_SYS_SYNTAX = rf'^(({_FKV}\s+)*{_S}(\s+{_FKV})*|{_FKV}(\s+{_FKV})*)$'
_SE = rf'({_N}(:{_N})?)' # system/partition (exact match; no wildcards)
# Valid syntax variants
#
# _SV1: system/partition combinations w/ wildcards
# _SV2: features and extras only
# _SV3: exact system/partition w/ features and extras
_SV1 = rf'{_S}'
_SV2 = rf'{_FKV}(\s+{_FKV})*'
_SV3 = rf'({_FKV}\s+)*{_SE}(\s+{_FKV})*'
_VALID_SYS_SYNTAX = rf'^({_SV1}|{_SV2}|{_SV3})$'

elif subspec.startswith('%'):
key, val = subspec[1:].split('=')
props[key] = val
elif not subspec.startswith(('+', '-', '%')):
Copy link
Contributor

@vkarak vkarak Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an else here should be enough as the syntax spec is already validated agains the regex:

Suggested change
elif not subspec.startswith(('+', '-', '%')):
else:

Comment on lines +295 to +296
valid_matches = ['*', '*:*', sysname, f'{sysname}:*', f'*:{partname}',
f'{part.fullname}']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
valid_matches = ['*', '*:*', sysname, f'{sysname}:*', f'*:{partname}',
f'{part.fullname}']
syspart_matches = ['*', '*:*', sysname, f'{sysname}:*', f'*:{partname}',
f'{part.fullname}']

plus_feats = []
minus_feats = []
props = {}
syspart_match = True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this a valid_match. It starts as true and may be turned to false if an exact partition match is requested.

Suggested change
syspart_match = True
valid_match = True

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe adjust the comments too, if needed.

Comment on lines +341 to +344
if (
have_plus_feats and not have_minus_feats and have_props
and syspart_match
):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (
have_plus_feats and not have_minus_feats and have_props
and syspart_match
):
if (have_plus_feats and
not have_minus_feats and
have_props and
valid_match):

Comment on lines +362 to +363
hellotest.valid_systems = ['sys:part +x0']
hellotest.valid_systems = ['+x0 sys:part']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some more tests here:

Suggested change
hellotest.valid_systems = ['sys:part +x0']
hellotest.valid_systems = ['+x0 sys:part']
hellotest.valid_systems = ['sys:part +x0 +y0']
hellotest.valid_systems = ['sys:part +x0 +y0 %z0=w0']
hellotest.valid_systems = ['+x0 sys:part']
hellotest.valid_systems = ['+x0 sys:part +y0 %z0=w0']

Comment on lines 365 to 366
with pytest.raises(TypeError):
hellotest.valid_systems = ['']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And also add more tests for invalid syntaxes:

    with pytest.raises(TypeError):
        hellotest.valid_systems = ['sys:* +foo']

    with pytest.raises(TypeError):
        hellotest.valid_systems = ['*:part +foo']

    with pytest.raises(TypeError):
        hellotest.valid_systems = ['*:* +foo']

    with pytest.raises(TypeError):
        hellotest.valid_systems = ['* +foo']

    with pytest.raises(TypeError):
        hellotest.valid_systems = ['sys0:part0 sys0:part1 +foo']

    with pytest.raises(TypeError):
        hellotest.valid_systems = ['sys0:part0 +foo sys0:part1']

    with pytest.raises(TypeError):
        hellotest.valid_systems = ['+foo sys0:part0 sys0:part1']

@github-project-automation github-project-automation bot moved this from Todo to In Progress in ReFrame Backlog Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

4 participants