1919from builtins import str , bytes
2020from packaging .version import Version
2121
22+ from traits .trait_errors import TraitError
23+ from traits .trait_handlers import TraitDictObject , TraitListObject
2224from ...utils .filemanip import md5 , hash_infile , hash_timestamp , to_str
2325from .traits_extension import (
2426 traits ,
2527 Undefined ,
2628 isdefined ,
27- TraitError ,
28- TraitDictObject ,
29- TraitListObject ,
3029 has_metadata ,
3130)
3231
3332from ... import config , __version__
3433
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+
3542FLOAT_FORMAT = '{:.10f}' .format
3643nipype_version = Version (__version__ )
3744
@@ -314,6 +321,39 @@ def __all__(self):
314321 return self .copyable_trait_names ()
315322
316323
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+
317357class TraitedSpec (BaseTraitedSpec ):
318358 """ Create a subclass with strict traits.
319359
@@ -333,29 +373,9 @@ class DynamicTraitedSpec(BaseTraitedSpec):
333373 functioning well together.
334374 """
335375
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
359379
360380
361381class CommandLineInputSpec (BaseInterfaceInputSpec ):
0 commit comments