Skip to content

Commit 4323870

Browse files
committed
correctly handle weirdly indented comments (and restore them with correct indent in dumped easyconfig)
1 parent 74b0338 commit 4323870

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

easybuild/framework/easyconfig/format/one.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,10 @@ def _get_item_comments(self, key, val):
231231
"""Get per-item comments for specified parameter name/value."""
232232
item_comments = {}
233233

234-
for comment_key, comment_val in self.comments['iterabove'].get(key, {}).items():
234+
cand_above_comments = self.comments['iterabove'].get(key, {}).items()
235+
cand_above_comments.extend(self.comments['above'].items())
236+
237+
for comment_key, comment_val in cand_above_comments:
235238
if str(val) in comment_key:
236239
item_comments['above'] = comment_val
237240

@@ -350,6 +353,7 @@ def extract_comments(self, rawtxt):
350353

351354
parsed_ec = self.get_config_dict()
352355

356+
comment_regex = re.compile(r'^\s*#')
353357
param_def_regex = re.compile(r'^([a-z_0-9]+)\s*=')
354358
whitespace_regex = re.compile(r'^\s*$')
355359

@@ -378,12 +382,12 @@ def split_on_comment_hash(line, param_key):
378382

379383
return before_comment, comment.strip()
380384

381-
def grab_more_comment_lines(lines, indent, param_key):
382-
"""Grab more comment lines that match specified indent."""
385+
def grab_more_comment_lines(lines, param_key):
386+
"""Grab more comment lines."""
383387

384388
comment_lines = []
385389

386-
while lines and (lines[0].startswith(indent + '#') or whitespace_regex.match(lines[0])):
390+
while lines and (comment_regex.match(lines[0]) or whitespace_regex.match(lines[0])):
387391
line = lines.pop(0)
388392
_, actual_comment = split_on_comment_hash(line, param_key)
389393
# prefix comment with '#' unless line was empty
@@ -396,7 +400,7 @@ def grab_more_comment_lines(lines, indent, param_key):
396400
rawlines = rawtxt.split('\n')
397401

398402
# extract header first (include empty lines too)
399-
self.comments['header'] = grab_more_comment_lines(rawlines, '', None)
403+
self.comments['header'] = grab_more_comment_lines(rawlines, None)
400404

401405
last_param_key = None
402406
while rawlines:
@@ -418,7 +422,7 @@ def grab_more_comment_lines(lines, indent, param_key):
418422

419423
# lines that start with a hash indicate (start of a block of) comment line(s)
420424
if rawline.startswith('#'):
421-
comment = [rawline] + grab_more_comment_lines(rawlines, '', last_param_key)
425+
comment = [rawline] + grab_more_comment_lines(rawlines, last_param_key)
422426

423427
if rawlines:
424428
# try to pin comment to parameter definition below it
@@ -430,7 +434,8 @@ def grab_more_comment_lines(lines, indent, param_key):
430434
else:
431435
# if the comment is not above a parameter definition,
432436
# just use the whole next line to determine where the comment belongs...
433-
self.comments['above'][rawlines[0]] = comment
437+
before_comment, _ = split_on_comment_hash(rawlines[0], last_param_key)
438+
self.comments['above'][before_comment.rstrip()] = comment
434439
else:
435440
# if there are no more lines, the comment (block) is at the tail
436441
self.comments['tail'] = comment
@@ -454,7 +459,7 @@ def grab_more_comment_lines(lines, indent, param_key):
454459
# then we have an indented comment, and we need to figure out for what exactly
455460
elif whitespace_regex.match(before_comment):
456461
# first consume possible additional comment lines with same indentation
457-
comment = [comment] + grab_more_comment_lines(rawlines, before_comment, last_param_key)
462+
comment = [comment] + grab_more_comment_lines(rawlines, last_param_key)
458463

459464
before_comment, inline_comment = split_on_comment_hash(rawlines.pop(0), last_param_key)
460465
comment_key = before_comment.rstrip()

test/framework/easyconfig.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,7 @@ def test_dump_comments(self):
18991899
"# this is a header",
19001900
"#",
19011901
"# which may include empty comment lines",
1902+
" # weirdly indented lines",
19021903
'',
19031904
"# or flat out empty lines",
19041905
'',
@@ -1925,6 +1926,7 @@ def test_dump_comments(self):
19251926
"source_urls = [",
19261927
" # first possible source URL",
19271928
" 'https://example.com',",
1929+
"# annoying non-indented comment",
19281930
" 'https://anotherexample.com', # fallback URL",
19291931
"]",
19301932
'',
@@ -1933,7 +1935,8 @@ def test_dump_comments(self):
19331935
"# multi > 3",
19341936
"dependencies = [",
19351937
" # this dependency",
1936-
" # has multiple lines above it",
1938+
"# has multiple lines above it",
1939+
" # some of which without proper indentation...",
19371940
" ('foo', '1.2.3'), # and an inline comment too",
19381941
" ('nocomment', '4.5'),",
19391942
" # last dependency, I promise",
@@ -1961,6 +1964,7 @@ def test_dump_comments(self):
19611964

19621965
# check internal structure to keep track of comments
19631966
self.assertEqual(ec.parser._formatter.comments['above'], {
1967+
" 'https://anotherexample.com',": ['# annoying non-indented comment'],
19641968
'dependencies': [
19651969
'# this is a multiline comment above dependencies',
19661970
'# I said multiline',
@@ -1977,6 +1981,7 @@ def test_dump_comments(self):
19771981
'# this is a header',
19781982
'#',
19791983
'# which may include empty comment lines',
1984+
'# weirdly indented lines',
19801985
'',
19811986
'# or flat out empty lines',
19821987
'',
@@ -1988,7 +1993,8 @@ def test_dump_comments(self):
19881993
self.assertEqual(ec.parser._formatter.comments['iterabove'], {
19891994
'dependencies': {
19901995
" ('foo', '1.2.3'),": ['# this dependency',
1991-
'# has multiple lines above it'],
1996+
'# has multiple lines above it',
1997+
"# some of which without proper indentation..."],
19921998
" ('last', '1.2.3'),": ['# last dependency, I promise'],
19931999
']': ['# trailing comments in dependencies', '# a bit weird, but it happens'],
19942000
},
@@ -2029,6 +2035,7 @@ def test_dump_comments(self):
20292035
'# this is a header',
20302036
'#',
20312037
'# which may include empty comment lines',
2038+
'# weirdly indented lines',
20322039
'',
20332040
'# or flat out empty lines',
20342041
'',
@@ -2081,6 +2088,7 @@ def test_dump_comments(self):
20812088
r'',
20822089
r" # this dependency",
20832090
r" # has multiple lines above it",
2091+
r" # some of which without proper indentation\.\.\.",
20842092
r" \('foo', '1\.2\.3'\), # and an inline comment too",
20852093
]),
20862094
'\n'.join([
@@ -2103,6 +2111,11 @@ def test_dump_comments(self):
21032111
r" # first possible source URL",
21042112
r" 'https://example\.com',",
21052113
]),
2114+
'\n'.join([
2115+
'',
2116+
r" # annoying non-indented comment",
2117+
r" 'https://anotherexample\.com', # fallback URL",
2118+
]),
21062119
]
21072120
for pattern in patterns:
21082121
regex = re.compile(pattern, re.M)

0 commit comments

Comments
 (0)