[python-debian/master 1/2] changelog: Use debian_support.Version directly

John Wright jsw at debian.org
Sun Mar 14 08:54:31 UTC 2010


When implementing the native Python Version class, I didn't notice that
changelog subclasses debian_support.Version and adds a bunch of
properties to it.  I had already implemented most of those in
debian_support.BaseVersion, but I hadn't made the properties mutable.
This commit makes them mutable, makes the debian_version property
equivalent to debian_revision, and makes changelog.Version a subclass
without any custom methods.

Now we pass the full test suite again. :)  Eventually, the version tests
in test_changelog.py should probably be split out into their own module
and test debian_support.AptPkgVersion and debian_support.NativeVersion
explicitly.  But I'll leave that for later.
---
 debian/changelog                |    3 ++
 debian/rules                    |    2 +-
 debian_bundle/changelog.py      |   65 ++----------------------------------
 debian_bundle/debian_support.py |   70 ++++++++++++++++++++++++++++++++-------
 4 files changed, 66 insertions(+), 74 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index c842014..4dd43ec 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -37,6 +37,9 @@ python-debian (0.1.15) UNRELEASED; urgency=low
   [ Jelmer Vernooij ]
   * Remove unused imports in the debfile and debtags modules
 
+  [ John Wright ]
+  * changelog: Use debian_support.Version directly
+
  -- John Wright <jsw at debian.org>  Sat, 13 Mar 2010 21:53:18 -0700
 
 python-debian (0.1.14) unstable; urgency=low
diff --git a/debian/rules b/debian/rules
index 6ce409f..0c3d7bc 100755
--- a/debian/rules
+++ b/debian/rules
@@ -22,7 +22,7 @@ build-stamp: setup.py
 	cd tests && ./test_debtags.py
 	cd tests && ./test_changelog.py
 
-	#python debian_bundle/python_support.py
+	python debian_bundle/debian_support.py
 	debian_bundle/doc-debtags > README.debtags
 
 	touch $@
diff --git a/debian_bundle/changelog.py b/debian_bundle/changelog.py
index e64cc3c..9ef7c49 100644
--- a/debian_bundle/changelog.py
+++ b/debian_bundle/changelog.py
@@ -53,67 +53,9 @@ class VersionError(StandardError):
     def __str__(self):
         return "Could not parse version: "+self._version
 
-class Version(debian_support.Version, object):
+class Version(debian_support.Version):
     """Represents a version of a Debian package."""
-    # Subclassing debian_support.Version for its rich comparison
-
-    def __init__(self, version):
-        version = str(version)
-        debian_support.Version.__init__(self, version)
-
-        self.full_version = version
-
-    def __setattr__(self, attr, value):
-      """Update all the attributes, given a particular piece of the version
-  
-      Allowable values for attr, hopefully self-explanatory:
-        full_version
-        epoch
-        upstream_version
-        debian_version
-
-      Any attribute starting with __ is given to object's __setattr__ method.
-      """
-
-      attrs = ('full_version', 'epoch', 'upstream_version', 'debian_version')
-
-      if attr.startswith('_Version__'):
-          object.__setattr__(self, attr, value)
-          return
-      elif attr not in attrs:
-          raise AttributeError("Cannot assign to attribute " + attr)
-
-      if attr == 'full_version':
-          version = value
-          p = re.compile(r'^(?:(?P<epoch>\d+):)?'
-                         + r'(?P<upstream_version>[A-Za-z0-9.+:~-]+?)'
-                         + r'(?:-(?P<debian_version>[A-Za-z0-9.~+]+))?$')
-          m = p.match(version)
-          if m is None:
-              raise VersionError(version)
-          for key, value in m.groupdict().items():
-              object.__setattr__(self, key, value)
-          self.__asString = version
-    
-      else:
-          # Construct a full version from what was given and pass it back here
-          d = {}
-          for a in attrs[1:]:
-              if a == attr:
-                  d[a] = value
-              else:
-                  d[a] = getattr(self, a)
-
-          version = ""
-          if d['epoch'] and d['epoch'] != '0':
-              version += d['epoch'] + ":"
-          version += d['upstream_version']
-          if d['debian_version']:
-              version += '-' + d['debian_version']
-
-          self.full_version = version
-
-    full_version = property(lambda self: self.__asString)
+    # debian_support.Version now has all the functionality we need
 
 class ChangeBlock(object):
     """Holds all the information about one block from the changelog."""
@@ -465,7 +407,8 @@ class Changelog(object):
     ### For convenience, let's expose some of the version properties
     full_version = property(lambda self: self.version.full_version)
     epoch = property(lambda self: self.version.epoch)
-    debian_version = property(lambda self: self.version.debian_version)
+    debian_version = property(lambda self: self.version.debian_revision)
+    debian_revision = property(lambda self: self.version.debian_revision)
     upstream_version = property(lambda self: self.version.upstream_version)
 
     def get_package(self):
diff --git a/debian_bundle/debian_support.py b/debian_bundle/debian_support.py
index 48d2eee..d216bba 100644
--- a/debian_bundle/debian_support.py
+++ b/debian_bundle/debian_support.py
@@ -71,8 +71,10 @@ class BaseVersion(object):
     according to Section 5.6.12 in the Debian Policy Manual.  Since splitting
     the version into epoch, upstream_version, and debian_revision components is
     pretty much free with the validation, it sets those fields as properties of
-    the object.  A missing epoch or debian_revision results in the respective
-    property set to "0".  These properties are immutable.
+    the object, and sets the raw version to the full_version property.  A
+    missing epoch or debian_revision results in the respective property set to
+    None.  Setting any of the properties results in the full_version being
+    recomputed and the rest of the properties set from that.
 
     It also implements __str__, just returning the raw version given to the
     initializer.
@@ -82,26 +84,70 @@ class BaseVersion(object):
             r"^((?P<epoch>\d+):)?"
              "(?P<upstream_version>[A-Za-z0-9.+:~-]+?)"
              "(-(?P<debian_revision>[A-Za-z0-9+.~]+))?$")
+    magic_attrs = ('full_version', 'epoch', 'upstream_version',
+                   'debian_revision', 'debian_version')
 
     def __init__(self, version):
-        if not isinstance(version, (str, unicode)):
-            raise ValueError, "version must be a string or unicode object"
+        self.full_version = version
 
+    def _set_full_version(self, version):
         m = self.re_valid_version.match(version)
         if not m:
             raise ValueError("Invalid version string %r" % version)
 
-        self.__raw_version = version
+        self.__full_version = version
         self.__epoch = m.group("epoch")
         self.__upstream_version = m.group("upstream_version")
         self.__debian_revision = m.group("debian_revision")
 
-    epoch = property(lambda self: self.__epoch or "0")
-    upstream_version = property(lambda self: self.__upstream_version)
-    debian_revision = property(lambda self: self.__debian_revision or "0")
+    def __setattr__(self, attr, value):
+        if attr not in self.magic_attrs:
+            super(BaseVersion, self).__setattr__(attr, value)
+            return
+
+        # For compatibility with the old changelog.Version class
+        if attr == "debian_version":
+            attr = "debian_revision"
+
+        if attr == "full_version":
+            self._set_full_version(str(value))
+        else:
+            if value is not None:
+                value = str(value)
+            private = "_BaseVersion__%s" % attr
+            old_value = getattr(self, private)
+            setattr(self, private, value)
+            try:
+                self._update_full_version()
+            except ValueError:
+                # Don't leave it in an invalid state
+                setattr(self, private, old_value)
+                self._update_full_version()
+                raise ValueError("Setting %s to %r results in invalid version"
+                                 % (attr, value))
+
+    def __getattr__(self, attr):
+        if attr not in self.magic_attrs:
+            return super(BaseVersion, self).__getattribute__(attr)
+
+        # For compatibility with the old changelog.Version class
+        if attr == "debian_version":
+            attr = "debian_revision"
+
+        private = "_BaseVersion__%s" % attr
+        return getattr(self, private)
+
+    def _update_full_version(self):
+        version = ""
+        if self.__epoch is not None:
+            version += self.__epoch + ":"
+        version += self.__upstream_version
+        if self.__debian_revision:
+            version += "-" + self.__debian_revision
+        self.full_version = version
 
     def __str__(self):
-        return self.__raw_version
+        return self.full_version
 
     def __repr__(self):
         return "%s('%s')" % (self.__class__.__name__, self)
@@ -140,15 +186,15 @@ class NativeVersion(BaseVersion):
                 raise ValueError("Couldn't convert %r to BaseVersion: %s"
                                  % (other, e))
 
-        res = cmp(int(self.epoch), int(other.epoch))
+        res = cmp(int(self.epoch or "0"), int(other.epoch or "0"))
         if res != 0:
             return res
         res = self._version_cmp_part(self.upstream_version,
                                      other.upstream_version)
         if res != 0:
             return res
-        return self._version_cmp_part(self.debian_revision,
-                                      other.debian_revision)
+        return self._version_cmp_part(self.debian_revision or "0",
+                                      other.debian_revision or "0")
 
     @classmethod
     def _order(cls, x):
-- 
1.6.3.3





More information about the pkg-python-debian-commits mailing list