|
20 | 20 |
|
21 | 21 | from builtins import str, bytes
|
22 | 22 | import os
|
| 23 | +import collections |
23 | 24 |
|
24 | 25 | # perform all external trait imports here
|
25 | 26 | from traits import __version__ as traits_version
|
|
30 | 31 |
|
31 | 32 | from traits.api import BaseUnicode
|
32 | 33 | from traits.api import Unicode
|
| 34 | +from future import standard_library |
| 35 | + |
33 | 36 | if traits_version < '3.7.0':
|
34 | 37 | raise ImportError('Traits version 3.7.0 or higher must be installed')
|
35 | 38 |
|
| 39 | +standard_library.install_aliases() |
| 40 | + |
36 | 41 | DictStrStr = traits.Dict((bytes, str), (bytes, str))
|
37 | 42 |
|
38 | 43 |
|
39 |
| -class Str(traits.Unicode): |
| 44 | +class Str(Unicode): |
40 | 45 | """Replacement for the default traits.Str based in bytes"""
|
41 | 46 |
|
42 | 47 |
|
@@ -234,16 +239,17 @@ def __init__(self, value='', auto_set=False, entries=0,
|
234 | 239 | # - uncompressed (tuple[0]) extension
|
235 | 240 | # - compressed (tuple[1]) extension
|
236 | 241 | img_fmt_types = {
|
237 |
| - 'nifti1': [('.nii', '.nii.gz'), |
238 |
| - (('.hdr', '.img'), ('.hdr', '.img.gz'))], |
239 |
| - 'mgh': [('.mgh', '.mgz'), ('.mgh', '.mgh.gz')], |
240 |
| - 'nifti2': [('.nii', '.nii.gz')], |
241 |
| - 'cifti2': [('.nii', '.nii.gz')], |
242 |
| - 'gifti': [('.gii', '.gii.gz')], |
243 |
| - 'dicom': [('.dcm', '.dcm'), ('.IMA', '.IMA'), ('.tar', '.tar.gz')], |
244 |
| - 'nrrd': [('.nrrd', 'nrrd'), ('nhdr', 'nhdr')], |
245 |
| - 'afni': [('.HEAD', '.HEAD'), ('.BRIK', '.BRIK')] |
246 |
| - } |
| 242 | + 'nifti1': [('.nii', '.nii.gz'), |
| 243 | + (('.hdr', '.img'), ('.hdr', '.img.gz'))], |
| 244 | + 'mgh': [('.mgh', '.mgz'), ('.mgh', '.mgh.gz')], |
| 245 | + 'nifti2': [('.nii', '.nii.gz')], |
| 246 | + 'cifti2': [('.nii', '.nii.gz')], |
| 247 | + 'gifti': [('.gii', '.gii.gz')], |
| 248 | + 'dicom': [('.dcm', '.dcm'), ('.IMA', '.IMA'), ('.tar', '.tar.gz')], |
| 249 | + 'nrrd': [('.nrrd', 'nrrd'), ('nhdr', 'nhdr')], |
| 250 | + 'afni': [('.HEAD', '.HEAD'), ('.BRIK', '.BRIK')] |
| 251 | +} |
| 252 | + |
247 | 253 |
|
248 | 254 | class ImageFile(File):
|
249 | 255 | """ Defines a trait of specific neuroimaging files """
|
@@ -341,3 +347,117 @@ def has_metadata(trait, metadata, value=None, recursive=True):
|
341 | 347 | count += has_metadata(handler, metadata, recursive)
|
342 | 348 |
|
343 | 349 | return count > 0
|
| 350 | + |
| 351 | + |
| 352 | +class MultiPath(traits.List): |
| 353 | + """ Abstract class - shared functionality of input and output MultiPath |
| 354 | + """ |
| 355 | + |
| 356 | + def validate(self, object, name, value): |
| 357 | + |
| 358 | + # want to treat range and other sequences (except str) as list |
| 359 | + if not isinstance(value, (str, bytes)) and isinstance(value, collections.Sequence): |
| 360 | + value = list(value) |
| 361 | + |
| 362 | + if not isdefined(value) or \ |
| 363 | + (isinstance(value, list) and len(value) == 0): |
| 364 | + return Undefined |
| 365 | + |
| 366 | + newvalue = value |
| 367 | + |
| 368 | + if not isinstance(value, list) \ |
| 369 | + or (self.inner_traits() and |
| 370 | + isinstance(self.inner_traits()[0].trait_type, |
| 371 | + traits.List) and not |
| 372 | + isinstance(self.inner_traits()[0].trait_type, |
| 373 | + InputMultiPath) and |
| 374 | + isinstance(value, list) and |
| 375 | + value and not |
| 376 | + isinstance(value[0], list)): |
| 377 | + newvalue = [value] |
| 378 | + value = super(MultiPath, self).validate(object, name, newvalue) |
| 379 | + |
| 380 | + if value: |
| 381 | + return value |
| 382 | + |
| 383 | + self.error(object, name, value) |
| 384 | + |
| 385 | + |
| 386 | +class OutputMultiPath(MultiPath): |
| 387 | + """ Implements a user friendly traits that accepts one or more |
| 388 | + paths to files or directories. This is the output version which |
| 389 | + return a single string whenever possible (when it was set to a |
| 390 | + single value or a list of length 1). Default value of this trait |
| 391 | + is _Undefined. It does not accept empty lists. |
| 392 | +
|
| 393 | + XXX This should only be used as a final resort. We should stick to |
| 394 | + established Traits to the extent possible. |
| 395 | +
|
| 396 | + XXX This needs to be vetted by somebody who understands traits |
| 397 | +
|
| 398 | + >>> from nipype.interfaces.base import OutputMultiPath |
| 399 | + >>> class A(TraitedSpec): |
| 400 | + ... foo = OutputMultiPath(File(exists=False)) |
| 401 | + >>> a = A() |
| 402 | + >>> a.foo |
| 403 | + <undefined> |
| 404 | +
|
| 405 | + >>> a.foo = '/software/temp/foo.txt' |
| 406 | + >>> a.foo |
| 407 | + '/software/temp/foo.txt' |
| 408 | +
|
| 409 | + >>> a.foo = ['/software/temp/foo.txt'] |
| 410 | + >>> a.foo |
| 411 | + '/software/temp/foo.txt' |
| 412 | +
|
| 413 | + >>> a.foo = ['/software/temp/foo.txt', '/software/temp/goo.txt'] |
| 414 | + >>> a.foo |
| 415 | + ['/software/temp/foo.txt', '/software/temp/goo.txt'] |
| 416 | +
|
| 417 | + """ |
| 418 | + |
| 419 | + def get(self, object, name): |
| 420 | + value = self.get_value(object, name) |
| 421 | + if len(value) == 0: |
| 422 | + return Undefined |
| 423 | + elif len(value) == 1: |
| 424 | + return value[0] |
| 425 | + else: |
| 426 | + return value |
| 427 | + |
| 428 | + def set(self, object, name, value): |
| 429 | + self.set_value(object, name, value) |
| 430 | + |
| 431 | + |
| 432 | +class InputMultiPath(MultiPath): |
| 433 | + """ Implements a user friendly traits that accepts one or more |
| 434 | + paths to files or directories. This is the input version which |
| 435 | + always returns a list. Default value of this trait |
| 436 | + is _Undefined. It does not accept empty lists. |
| 437 | +
|
| 438 | + XXX This should only be used as a final resort. We should stick to |
| 439 | + established Traits to the extent possible. |
| 440 | +
|
| 441 | + XXX This needs to be vetted by somebody who understands traits |
| 442 | +
|
| 443 | + >>> from nipype.interfaces.base import InputMultiPath |
| 444 | + >>> class A(TraitedSpec): |
| 445 | + ... foo = InputMultiPath(File(exists=False)) |
| 446 | + >>> a = A() |
| 447 | + >>> a.foo |
| 448 | + <undefined> |
| 449 | +
|
| 450 | + >>> a.foo = '/software/temp/foo.txt' |
| 451 | + >>> a.foo |
| 452 | + ['/software/temp/foo.txt'] |
| 453 | +
|
| 454 | + >>> a.foo = ['/software/temp/foo.txt'] |
| 455 | + >>> a.foo |
| 456 | + ['/software/temp/foo.txt'] |
| 457 | +
|
| 458 | + >>> a.foo = ['/software/temp/foo.txt', '/software/temp/goo.txt'] |
| 459 | + >>> a.foo |
| 460 | + ['/software/temp/foo.txt', '/software/temp/goo.txt'] |
| 461 | +
|
| 462 | + """ |
| 463 | + pass |
0 commit comments