[blivet:master] Factor duplicate code in __deepcopy__ methods into one method (#1095244)

mulhern amulhern at redhat.com
Fri May 9 16:39:43 UTC 2014


Related: fed#1095244

The method treats attributes in omit and attributes w/ value None the
same way.  Previously, an attribute with a None value was not handled
specially, which could lead to "NoneType has no attribute <x>"
sorts of errors.

Signed-off-by: mulhern <amulhern at redhat.com>
---
 blivet/devices.py           | 16 +++-------------
 blivet/formats/disklabel.py | 19 ++++---------------
 blivet/util.py              | 38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 28 deletions(-)

diff --git a/blivet/devices.py b/blivet/devices.py
index 256d830..009d127 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -249,19 +249,9 @@ class Device(util.ObjectID):
             We can't do copy.deepcopy on parted objects, which is okay.
             For these parted objects, we just do a shallow copy.
         """
-        new = self.__class__.__new__(self.__class__)
-        memo[id(self)] = new
-        dont_copy_attrs = ('_raidSet', 'node')
-        shallow_copy_attrs = ('_partedDevice', '_partedPartition')
-        for (attr, value) in self.__dict__.items():
-            if attr in dont_copy_attrs:
-                setattr(new, attr, value)
-            elif attr in shallow_copy_attrs:
-                setattr(new, attr, copy.copy(value))
-            else:
-                setattr(new, attr, copy.deepcopy(value, memo))
-
-        return new
+        return util.variable_copy(self, memo,
+           omit=('_raidSet', 'node'),
+           shallow=('_partedDevice', '_partedPartition'))
 
     def __repr__(self):
         s = ("%(type)s instance (%(id)s) --\n"
diff --git a/blivet/formats/disklabel.py b/blivet/formats/disklabel.py
index e06c39f..a7609aa 100644
--- a/blivet/formats/disklabel.py
+++ b/blivet/formats/disklabel.py
@@ -21,13 +21,13 @@
 #
 
 import os
-import copy
 
 from ..storage_log import log_exception_info, log_method_call
 import parted
 import _ped
 from ..errors import DeviceFormatError, DiskLabelCommitError, InvalidDiskLabelError
 from .. import arch
+from .. import util
 from ..flags import flags
 from ..udev import udev_settle
 from ..i18n import _, N_
@@ -78,21 +78,10 @@ class DiskLabel(DeviceFormat):
         """ Create a deep copy of a Disklabel instance.
 
             We can't do copy.deepcopy on parted objects, which is okay.
-            For these parted objects, we just do a shallow copy.
         """
-        new = self.__class__.__new__(self.__class__)
-        memo[id(self)] = new
-        shallow_copy_attrs = ('_partedDevice', '_alignment', '_endAlignment')
-        duplicate_attrs = ('_partedDisk', '_origPartedDisk')
-        for (attr, value) in self.__dict__.items():
-            if attr in shallow_copy_attrs:
-                setattr(new, attr, copy.copy(value))
-            elif attr in duplicate_attrs:
-                setattr(new, attr, value.duplicate())
-            else:
-                setattr(new, attr, copy.deepcopy(value, memo))
-
-        return new
+        return util.variable_copy(self, memo,
+           shallow=('_partedDevice', '_alignment', '_endAlignment'),
+           duplicate=('_partedDisk', '_origPartedDisk'))
 
     def __repr__(self):
         s = DeviceFormat.__repr__(self)
diff --git a/blivet/util.py b/blivet/util.py
index 1fd5035..6b9fed6 100644
--- a/blivet/util.py
+++ b/blivet/util.py
@@ -1,3 +1,4 @@
+import copy
 import itertools
 import os
 import shutil
@@ -353,3 +354,40 @@ class ObjectID(object):
         self = super(ObjectID, cls).__new__(cls, *args, **kwargs)
         self.id = self._newid_gen() # pylint: disable=attribute-defined-outside-init
         return self
+
+def variable_copy(obj, memo, omit=None, shallow=None, duplicate=None):
+    """ A configurable copy function. Any attributes not specified in omit,
+        shallow, or duplicate are copied using copy.deepcopy().
+
+        :param object obj: a python object to be copied.
+        :param dict memo: a dictionary of already copied items
+        :param omit: a list of names of attributes not to copy
+        :type omit: iterable of str
+        :param shallow: a list of names of attributes to shallow copy
+        :type shallow: iterable of str
+        :param duplicate: a list of names of attributes to duplicate
+        :type duplicate: iterable of str
+
+        Note that all atrributes in duplicate must implement a duplicate()
+        method that does what is expected of it. Attributes with type
+        pyparted.Disk are known to do so.
+
+        A shallow copy is implemented by calling copy.copy().
+    """
+    omit = omit or []
+    shallow = shallow or []
+    duplicate = duplicate or []
+
+    new = obj.__class__.__new__(obj.__class__)
+    memo[id(obj)] = new
+    for (attr, value) in obj.__dict__.items():
+        if attr in omit or value == None:
+            setattr(new, attr, value)
+        elif attr in shallow:
+            setattr(new, attr, copy.copy(value))
+        elif attr in duplicate:
+            setattr(new, attr, value.duplicate())
+        else:
+            setattr(new, attr, copy.deepcopy(value, memo))
+
+    return new
-- 
1.8.3.1



More information about the anaconda-patches mailing list