Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bugfix] Treat node name suffixes properly in abbreviated node lists #3027

Merged
merged 1 commit into from
Oct 24, 2023
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
37 changes: 24 additions & 13 deletions reframe/utility/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -829,11 +829,12 @@ def _rl_encode(seq):


def _parse_node(nodename):
m = re.search(r'(.*\D)(\d+)', nodename)
m = re.search(r'(.*\D)(\d+)(\D*)', nodename)
if m is None:
basename = nodename
width = 0
nodeid = None
suffix = None
else:
basename = m.group(1)
_id = m.group(2).lstrip('0')
Expand All @@ -843,8 +844,9 @@ def _parse_node(nodename):

nodeid = int(_id)
width = len(m.group(2))
suffix = m.group(3)

return basename, width, nodeid
return basename, width, nodeid, suffix


def count_digits(n):
Expand Down Expand Up @@ -873,15 +875,20 @@ def _common_prefix(s1, s2):


class _NodeGroup:
def __init__(self, name, width):
def __init__(self, name, width, suffix):
self.__name = name
self.__suffix = suffix
self.__width = width
self.__nodes = []

@property
def name(self):
return self.__name

@property
def suffix(self):
return self.__suffix

@property
def width(self):
return self.__width
Expand All @@ -903,12 +910,12 @@ def __str__(self):
start, delta, size = unit
if size == 1:
s_start = str(start).zfill(self.width)
abbrev.append(f'{self.name}{s_start}')
abbrev.append(f'{self.name}{s_start}{self.suffix}')
elif delta != 1:
# We simply unpack node lists with delta != 1
for i in range(size):
s_start = str(start + i*delta).zfill(self.width)
abbrev.append(f'{self.name}{s_start}')
abbrev.append(f'{self.name}{s_start}{self.suffix}')
else:
last = start + delta*(size-1)
digits_last = count_digits(last)
Expand All @@ -921,19 +928,21 @@ def __str__(self):
s_first = str(start).zfill(digits_last)
s_last = str(last)
prefix, s_first, s_last = _common_prefix(s_first, s_last)
nd_range += f'{prefix}[{s_first}-{s_last}]'
nd_range += f'{prefix}[{s_first}-{s_last}]{self.suffix}'
abbrev.append(nd_range)

return ','.join(abbrev)

def __hash__(self):
return hash(self.name) ^ hash(self.width)
return hash(self.name) ^ hash(self.suffix) ^ hash(self.width)

def __eq__(self, other):
if not isinstance(other, _NodeGroup):
return NotImplemented

return self.name == other.name and self.width == other.width
return (self.name == other.name and
self.suffix == other.suffix and
self.width == other.width)


def nodelist_abbrev(nodes):
Expand Down Expand Up @@ -978,8 +987,8 @@ def nodelist_abbrev(nodes):

node_groups = {}
for n in sorted(nodes):
basename, width, nid = _parse_node(n)
ng = _NodeGroup(basename, width)
basename, width, nid, suffix = _parse_node(n)
ng = _NodeGroup(basename, width, suffix)
node_groups.setdefault(ng, ng)
if nid is not None:
node_groups[ng].add(nid)
Expand All @@ -1004,7 +1013,9 @@ def nodelist_expand(nodespec):
return []

nodespec_parts = nodespec.split(',')
node_patt = re.compile(r'(?P<prefix>.+)\[(?P<l>\d+)-(?P<u>\d+)\]')
node_patt = re.compile(
r'(?P<prefix>.+)\[(?P<l>\d+)-(?P<u>\d+)\](?P<suffix>.*)'
)
nodes = []
for ns in nodespec_parts:
if '[' not in ns and ']' not in ns:
Expand All @@ -1015,11 +1026,11 @@ def nodelist_expand(nodespec):
if not match:
raise ValueError(f'invalid nodespec: {nodespec}')

prefix = match.group('prefix')
prefix, suffix = match.group('prefix'), match.group('suffix')
low, upper = int(match.group('l')), int(match.group('u'))
width = count_digits(upper)
for nid in range(low, upper+1):
nodes.append(f'{prefix}{nid:0{width}}')
nodes.append(f'{prefix}{nid:0{width}}{suffix}')

return nodes

Expand Down
6 changes: 6 additions & 0 deletions unittests/test_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -2052,6 +2052,12 @@ def test_nodelist_utilities():
# Test the reverse operation
assert expand('c2-01-[00-99]') == nodes

# Test host names with suffixes (see GH #3021)
nodes = [f'nid{n:03}-x' for n in range(100)]
nodes.append('nid100-y')
assert nodelist(nodes) == 'nid0[00-99]-x,nid100-y'
assert expand('nid0[00-99]-x,nid100-y') == nodes

# Test node duplicates
assert nodelist(['nid001', 'nid001', 'nid002']) == 'nid001,nid00[1-2]'
assert expand('nid001,nid00[1-2]') == ['nid001', 'nid001', 'nid002']
Expand Down