19
19
from builtins import str , bytes
20
20
from packaging .version import Version
21
21
22
+ from traits .trait_errors import TraitError
23
+ from traits .trait_handlers import TraitDictObject , TraitListObject
22
24
from ...utils .filemanip import md5 , hash_infile , hash_timestamp , to_str
23
25
from .traits_extension import (
24
26
traits ,
25
27
Undefined ,
26
28
isdefined ,
27
- TraitError ,
28
- TraitDictObject ,
29
- TraitListObject ,
30
29
has_metadata ,
31
30
)
32
31
33
32
from ... import config , __version__
34
33
34
+
35
+ USING_PATHLIB2 = False
36
+ try :
37
+ from pathlib import Path
38
+ except ImportError :
39
+ from pathlib2 import Path # noqa
40
+ USING_PATHLIB2 = True
41
+
35
42
FLOAT_FORMAT = '{:.10f}' .format
36
43
nipype_version = Version (__version__ )
37
44
@@ -314,6 +321,39 @@ def __all__(self):
314
321
return self .copyable_trait_names ()
315
322
316
323
324
+ def _deepcopypatch (self , memo ):
325
+ """
326
+ Replace the ``__deepcopy__`` member with a traits-friendly implementation.
327
+
328
+ A bug in ``__deepcopy__`` for ``HasTraits`` results in weird cloning behaviors.
329
+ Occurs for all specs in Python<3 and only for DynamicTraitedSpec in Python>2.
330
+
331
+ """
332
+ id_self = id (self )
333
+ if id_self in memo :
334
+ return memo [id_self ]
335
+ dup_dict = deepcopy (self .trait_get (), memo )
336
+ # access all keys
337
+ for key in self .copyable_trait_names ():
338
+ if key in self .__dict__ .keys ():
339
+ _ = getattr (self , key )
340
+ # clone once
341
+ dup = self .clone_traits (memo = memo )
342
+ for key in self .copyable_trait_names ():
343
+ try :
344
+ _ = getattr (dup , key )
345
+ except :
346
+ pass
347
+ # clone twice
348
+ dup = self .clone_traits (memo = memo )
349
+ dup .trait_set (** dup_dict )
350
+ return dup
351
+
352
+
353
+ if USING_PATHLIB2 :
354
+ BaseTraitedSpec .__deepcopy__ = _deepcopypatch
355
+
356
+
317
357
class TraitedSpec (BaseTraitedSpec ):
318
358
""" Create a subclass with strict traits.
319
359
@@ -333,29 +373,9 @@ class DynamicTraitedSpec(BaseTraitedSpec):
333
373
functioning well together.
334
374
"""
335
375
336
- def __deepcopy__ (self , memo ):
337
- """ bug in deepcopy for HasTraits results in weird cloning behavior for
338
- added traits
339
- """
340
- id_self = id (self )
341
- if id_self in memo :
342
- return memo [id_self ]
343
- dup_dict = deepcopy (self .trait_get (), memo )
344
- # access all keys
345
- for key in self .copyable_trait_names ():
346
- if key in self .__dict__ .keys ():
347
- _ = getattr (self , key )
348
- # clone once
349
- dup = self .clone_traits (memo = memo )
350
- for key in self .copyable_trait_names ():
351
- try :
352
- _ = getattr (dup , key )
353
- except :
354
- pass
355
- # clone twice
356
- dup = self .clone_traits (memo = memo )
357
- dup .trait_set (** dup_dict )
358
- return dup
376
+
377
+ if not USING_PATHLIB2 :
378
+ DynamicTraitedSpec .__deepcopy__ = _deepcopypatch
359
379
360
380
361
381
class CommandLineInputSpec (BaseInterfaceInputSpec ):
0 commit comments