1919from builtins import str , bytes
2020from packaging .version import Version
2121
22- from ...utils .filemanip import md5 , hash_infile , hash_timestamp , to_str
22+ from traits .trait_errors import TraitError
23+ from traits .trait_handlers import TraitDictObject , TraitListObject
24+ from ...utils .filemanip import (
25+ md5 , hash_infile , hash_timestamp , to_str , USING_PATHLIB2 )
2326from .traits_extension import (
2427 traits ,
2528 Undefined ,
2629 isdefined ,
27- TraitError ,
28- TraitDictObject ,
29- TraitListObject ,
3030 has_metadata ,
3131)
3232
3333from ... import config , __version__
3434
35+
3536FLOAT_FORMAT = '{:.10f}' .format
3637nipype_version = Version (__version__ )
3738
@@ -314,6 +315,39 @@ def __all__(self):
314315 return self .copyable_trait_names ()
315316
316317
318+ def _deepcopypatch (self , memo ):
319+ """
320+ Replace the ``__deepcopy__`` member with a traits-friendly implementation.
321+
322+ A bug in ``__deepcopy__`` for ``HasTraits`` results in weird cloning behaviors.
323+ Occurs for all specs in Python<3 and only for DynamicTraitedSpec in Python>2.
324+
325+ """
326+ id_self = id (self )
327+ if id_self in memo :
328+ return memo [id_self ]
329+ dup_dict = deepcopy (self .trait_get (), memo )
330+ # access all keys
331+ for key in self .copyable_trait_names ():
332+ if key in self .__dict__ .keys ():
333+ _ = getattr (self , key )
334+ # clone once
335+ dup = self .clone_traits (memo = memo )
336+ for key in self .copyable_trait_names ():
337+ try :
338+ _ = getattr (dup , key )
339+ except :
340+ pass
341+ # clone twice
342+ dup = self .clone_traits (memo = memo )
343+ dup .trait_set (** dup_dict )
344+ return dup
345+
346+
347+ if USING_PATHLIB2 :
348+ BaseTraitedSpec .__deepcopy__ = _deepcopypatch
349+
350+
317351class TraitedSpec (BaseTraitedSpec ):
318352 """ Create a subclass with strict traits.
319353
@@ -333,29 +367,9 @@ class DynamicTraitedSpec(BaseTraitedSpec):
333367 functioning well together.
334368 """
335369
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
370+
371+ if not USING_PATHLIB2 :
372+ DynamicTraitedSpec .__deepcopy__ = _deepcopypatch
359373
360374
361375class CommandLineInputSpec (BaseInterfaceInputSpec ):
0 commit comments