|
25 | 25 | from ... import logging, config, LooseVersion
|
26 | 26 | from ...utils.filemanip import (
|
27 | 27 | Path,
|
| 28 | + indirectory, |
28 | 29 | relpath,
|
29 | 30 | makedirs,
|
30 | 31 | fname_presuffix,
|
31 | 32 | to_str,
|
32 | 33 | ensure_list,
|
33 | 34 | get_related_files,
|
34 |
| - FileNotFoundError, |
35 | 35 | save_json,
|
36 | 36 | savepkl,
|
37 | 37 | loadpkl,
|
|
41 | 41 | )
|
42 | 42 | from ...utils.misc import str2bool
|
43 | 43 | from ...utils.functions import create_function_from_source
|
44 |
| -from ...interfaces.base import (Bunch, CommandLine, isdefined, Undefined, |
45 |
| - InterfaceResult, traits) |
| 44 | +from ...interfaces.base.traits_extension import ( |
| 45 | + rebase_path_traits, resolve_path_traits, OutputMultiPath, isdefined, Undefined, traits) |
| 46 | +from ...interfaces.base.support import Bunch, InterfaceResult |
| 47 | +from ...interfaces.base import CommandLine |
46 | 48 | from ...interfaces.utility import IdentityInterface
|
47 | 49 | from ...utils.provenance import ProvStore, pm, nipype_ns, get_id
|
48 | 50 |
|
@@ -227,52 +229,101 @@ def write_report(node, report_type=None, is_mapnode=False):
|
227 | 229 | return
|
228 | 230 |
|
229 | 231 |
|
230 |
| -def save_resultfile(result, cwd, name): |
231 |
| - """Save a result pklz file to ``cwd``""" |
| 232 | +def save_resultfile(result, cwd, name, rebase=None): |
| 233 | + """Save a result pklz file to ``cwd``.""" |
| 234 | + if rebase is None: |
| 235 | + rebase = config.getboolean('execution', 'use_relative_paths') |
| 236 | + |
| 237 | + cwd = os.path.abspath(cwd) |
232 | 238 | resultsfile = os.path.join(cwd, 'result_%s.pklz' % name)
|
233 |
| - savepkl(resultsfile, result) |
234 |
| - logger.debug('saved results in %s', resultsfile) |
| 239 | + logger.debug("Saving results file: '%s'", resultsfile) |
235 | 240 |
|
| 241 | + if result.outputs is None: |
| 242 | + logger.warn('Storing result file without outputs') |
| 243 | + savepkl(resultsfile, result) |
| 244 | + return |
| 245 | + try: |
| 246 | + output_names = result.outputs.copyable_trait_names() |
| 247 | + except AttributeError: |
| 248 | + logger.debug('Storing non-traited results, skipping rebase of paths') |
| 249 | + savepkl(resultsfile, result) |
| 250 | + return |
236 | 251 |
|
237 |
| -def load_resultfile(results_file): |
| 252 | + backup_traits = {} |
| 253 | + try: |
| 254 | + with indirectory(cwd): |
| 255 | + # All the magic to fix #2944 resides here: |
| 256 | + for key in output_names: |
| 257 | + old = getattr(result.outputs, key) |
| 258 | + if isdefined(old): |
| 259 | + if result.outputs.trait(key).is_trait_type(OutputMultiPath): |
| 260 | + old = result.outputs.trait(key).handler.get_value( |
| 261 | + result.outputs, key) |
| 262 | + backup_traits[key] = old |
| 263 | + val = rebase_path_traits(result.outputs.trait(key), old, cwd) |
| 264 | + setattr(result.outputs, key, val) |
| 265 | + savepkl(resultsfile, result) |
| 266 | + finally: |
| 267 | + # Restore resolved paths from the outputs dict no matter what |
| 268 | + for key, val in list(backup_traits.items()): |
| 269 | + setattr(result.outputs, key, val) |
| 270 | + |
| 271 | + |
| 272 | +def load_resultfile(results_file, resolve=True): |
238 | 273 | """
|
239 |
| - Load InterfaceResult file from path |
| 274 | + Load InterfaceResult file from path. |
240 | 275 |
|
241 | 276 | Parameter
|
242 | 277 | ---------
|
243 |
| -
|
244 | 278 | path : base_dir of node
|
245 | 279 | name : name of node
|
246 | 280 |
|
247 | 281 | Returns
|
248 | 282 | -------
|
249 |
| -
|
250 | 283 | result : InterfaceResult structure
|
251 | 284 | aggregate : boolean indicating whether node should aggregate_outputs
|
252 | 285 | attribute error : boolean indicating whether there was some mismatch in
|
253 | 286 | versions of traits used to store result and hence node needs to
|
254 | 287 | rerun
|
| 288 | +
|
255 | 289 | """
|
256 |
| - aggregate = True |
257 | 290 | results_file = Path(results_file)
|
| 291 | + aggregate = True |
258 | 292 | result = None
|
259 | 293 | attribute_error = False
|
260 |
| - if results_file.exists(): |
| 294 | + |
| 295 | + if not results_file.exists(): |
| 296 | + return result, aggregate, attribute_error |
| 297 | + |
| 298 | + with indirectory(str(results_file.parent)): |
261 | 299 | try:
|
262 | 300 | result = loadpkl(results_file)
|
263 |
| - except (traits.TraitError, AttributeError, ImportError, |
264 |
| - EOFError) as err: |
265 |
| - if isinstance(err, (AttributeError, ImportError)): |
266 |
| - attribute_error = True |
267 |
| - logger.debug('attribute error: %s probably using ' |
268 |
| - 'different trait pickled file', str(err)) |
269 |
| - else: |
270 |
| - logger.debug( |
271 |
| - 'some file does not exist. hence trait cannot be set') |
| 301 | + except (traits.TraitError, EOFError): |
| 302 | + logger.debug( |
| 303 | + 'some file does not exist. hence trait cannot be set') |
| 304 | + except (AttributeError, ImportError) as err: |
| 305 | + attribute_error = True |
| 306 | + logger.debug('attribute error: %s probably using ' |
| 307 | + 'different trait pickled file', str(err)) |
272 | 308 | else:
|
273 | 309 | aggregate = False
|
274 | 310 |
|
275 |
| - logger.debug('Aggregate: %s', aggregate) |
| 311 | + if resolve and result.outputs: |
| 312 | + try: |
| 313 | + outputs = result.outputs.get() |
| 314 | + except TypeError: # This is a Bunch |
| 315 | + return result, aggregate, attribute_error |
| 316 | + |
| 317 | + logger.debug('Resolving paths in outputs loaded from results file.') |
| 318 | + for trait_name, old in list(outputs.items()): |
| 319 | + if isdefined(old): |
| 320 | + if result.outputs.trait(trait_name).is_trait_type(OutputMultiPath): |
| 321 | + old = result.outputs.trait(trait_name).handler.get_value( |
| 322 | + result.outputs, trait_name) |
| 323 | + value = resolve_path_traits(result.outputs.trait(trait_name), old, |
| 324 | + results_file.parent) |
| 325 | + setattr(result.outputs, trait_name, value) |
| 326 | + |
276 | 327 | return result, aggregate, attribute_error
|
277 | 328 |
|
278 | 329 |
|
|
0 commit comments