@@ -120,7 +120,18 @@ def handle_deprecated_or_replaced_easyconfig_parameters(ec_method):
120120 def new_ec_method (self , key , * args , ** kwargs ):
121121 """Check whether any replace easyconfig parameters are still used"""
122122 # map deprecated parameters to their replacements, issue deprecation warning(/error)
123- if key in ALTERNATIVE_EASYCONFIG_PARAMETERS :
123+ if key == 'parallel' :
124+ _log .deprecated ("Easyconfig parameter 'parallel' is deprecated, "
125+ "use 'max_parallel' or the parallel property instead." , '6.0' )
126+ # This hidden parameter allows easyblocks to continue using self.cfg['parallel'] which contains
127+ # the computed parallelism after the ready step but the easyconfig parameter before that step.
128+
129+ # Easyblocks using `max_parallel` always get the value from the easyconfig unmodified.
130+ # Easyblocks should use either the parallel property or `max_parallel` such that the semantic is clear.
131+ # In particular writes to self.cfg['parallel'] do NOT update the %(parallel)s template.
132+ # It can be removed when the deprecation expires.
133+ key = '_parallelLegacy'
134+ elif key in ALTERNATIVE_EASYCONFIG_PARAMETERS :
124135 key = ALTERNATIVE_EASYCONFIG_PARAMETERS [key ]
125136 elif key in DEPRECATED_EASYCONFIG_PARAMETERS :
126137 depr_key = key
@@ -144,7 +155,10 @@ def is_local_var_name(name):
144155 """
145156 res = False
146157 if name .startswith (LOCAL_VAR_PREFIX ) or name .startswith ('_' ):
147- res = True
158+ # make exception for '_parallelLegacy' hidden easyconfig parameter,
159+ # which is used to deprecate use of 'paralell' easyconfig parameter
160+ if name != '_parallelLegacy' :
161+ res = True
148162 # __builtins__ is always defined as a 'local' variables
149163 # single-letter local variable names are allowed (mainly for use in list comprehensions)
150164 # in Python 2, variables defined in list comprehensions leak to the outside (no longer the case in Python 3)
@@ -502,6 +516,12 @@ def __init__(self, path, extra_options=None, build_specs=None, validate=True, hi
502516 self .iterate_options = []
503517 self .iterating = False
504518
519+ # Storage for parallel property. Mark as unset initially
520+ self ._parallel = None
521+ # introduce hidden '_parallelLegacy' easyconfig parameter,
522+ # used to deprecate use of 'parallel' easyconfig parameter
523+ self ._config ['_parallelLegacy' ] = [None , '' , ('' , )]
524+
505525 # parse easyconfig file
506526 self .build_specs = build_specs
507527 self .parse ()
@@ -598,6 +618,7 @@ def copy(self, validate=None):
598618 ec = EasyConfig (self .path , validate = validate , hidden = self .hidden , rawtxt = self .rawtxt )
599619 # take a copy of the actual config dictionary (which already contains the extra options)
600620 ec ._config = copy .deepcopy (self ._config )
621+ ec ._parallel = self ._parallel # Might be already set, e.g. for extensions
601622 # since rawtxt is defined, self.path may not get inherited, make sure it does
602623 if self .path :
603624 ec .path = self .path
@@ -702,6 +723,12 @@ def parse(self):
702723 if missing_mandatory_keys :
703724 raise EasyBuildError ("mandatory parameters not provided in %s: %s" , self .path , missing_mandatory_keys )
704725
726+ if 'parallel' in ec_vars :
727+ # Replace value and issue better warning for easyconfig parameters,
728+ # as opposed to warnings meant for easyblocks)
729+ self .log .deprecated ("Easyconfig parameter 'parallel' is deprecated, use 'max_parallel' instead." , '6.0' )
730+ ec_vars ['_parallelLegacy' ] = ec_vars .pop ('parallel' )
731+
705732 # provide suggestions for typos. Local variable names are excluded from this check
706733 possible_typos = [(key , difflib .get_close_matches (key .lower (), self ._config .keys (), 1 , 0.85 ))
707734 for key in ec_vars if not is_local_var_name (key ) and key not in self ]
@@ -1235,6 +1262,32 @@ def all_dependencies(self):
12351262
12361263 return self ._all_dependencies
12371264
1265+ @property
1266+ def is_parallel_set (self ):
1267+ """Return if the desired parallelism has been determined yet"""
1268+ return self ._parallel is not None
1269+
1270+ @property
1271+ def parallel (self ):
1272+ """Degree of parallellism (number of cores) to be used for building, etc."""
1273+ if not self .is_parallel_set :
1274+ raise ValueError ("Parallelism not set yet, 'set_parallel' method of easyblock must be called first" )
1275+
1276+ # This gets set when an easyblock changes ec['parallel'].
1277+ # It also gets set/updated in set_parallel to mirror the old behavior during the deprecation phase
1278+ parallelLegacy = self ._config ['_parallelLegacy' ][0 ]
1279+ if parallelLegacy is not None :
1280+ return max (1 , parallelLegacy )
1281+ return self ._parallel
1282+
1283+ @parallel .setter
1284+ def parallel (self , value ):
1285+ # Update backstorage and template value
1286+ self ._parallel = max (1 , value ) # Also handles False
1287+ self .template_values ['parallel' ] = self ._parallel
1288+ # Backwards compatibility, only for easyblocks still reading self.cfg['parallel']
1289+ self ._config ['_parallelLegacy' ][0 ] = self ._parallel
1290+
12381291 def dump (self , fp , always_overwrite = True , backup = False , explicit_toolchains = False ):
12391292 """
12401293 Dump this easyconfig to file, with the given filename.
0 commit comments