[MERGE] Add __eq__ and __ne__ methods to Repository objects
Andrew Bennetts
andrew at canonical.com
Mon Aug 6 03:08:08 BST 2007
This bundle adds __eq__ and __ne__ methods to Repository objects so that you can
use the “==” and “!=” operators to tell if two objects are the same repository
or not. See the extensive repository_implementations tests I've added for the
exact semantics, although they should be fairly intuitive. This will be useful
in places like bzrlib/fetch.py that want to know if two repository objects
refer to the same repository or not.
This was written in response to John's review of my fetch-refactor bundle: he
suggested I should get rid of the _same_repo methods I added in fetch.py and
make Repositories comparable instead. I think he's right: it would be good to
get rid of that logic from fetch.py, and put it somewhere where other code can
use it.
-Andrew.
-------------- next part --------------
# Bazaar merge directive format 2 (Bazaar 0.19)
# revision_id: andrew.bennetts at canonical.com-20070806015955-\
# m36ovt3lahluxjzx
# target_branch: http://bazaar-vcs.org/bzr/bzr.dev
# testament_sha1: e7033d669c79a34ed51147d278190537fb89d897
# timestamp: 2007-08-06 12:00:20 +1000
# source_branch: http://people.ubuntu.com/~andrew/bzr/repository-\
# equality
# base_revision_id: pqm at pqm.ubuntu.com-20070803043116-l7u1uypblmx1uxnr
#
# Begin patch
=== modified file 'NEWS'
--- NEWS 2007-08-02 07:22:05 +0000
+++ NEWS 2007-08-06 01:59:55 +0000
@@ -195,6 +195,9 @@
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
files that are stored on a transport. (Robert Collins)
+ * ``Repository`` objects can now be compared with ``==`` and ``!=`` to
+ determine if they are the same repository. (Andrew Bennetts)
+
TESTING:
* Remove selftest ``--clean-output``, ``--numbered-dirs`` and
=== modified file 'bzrlib/remote.py'
--- bzrlib/remote.py 2007-07-25 00:52:21 +0000
+++ bzrlib/remote.py 2007-08-06 01:59:55 +0000
@@ -249,6 +249,13 @@
self._lock_count = 0
self._leave_lock = False
+ def __eq__(self, other):
+ return (self.__class__ == other.__class__ and
+ self._client == other._client)
+
+ def __ne__(self, other):
+ return not self == other
+
def _ensure_real(self):
"""Ensure that there is a _real_repository set.
=== modified file 'bzrlib/repository.py'
--- bzrlib/repository.py 2007-07-31 02:07:34 +0000
+++ bzrlib/repository.py 2007-08-06 01:59:55 +0000
@@ -235,6 +235,15 @@
return '%s(%r)' % (self.__class__.__name__,
self.bzrdir.transport.base)
+ def __eq__(self, other):
+ if self.__class__ is not other.__class__:
+ return False
+ return (self.control_files._transport.base ==
+ other.control_files._transport.base)
+
+ def __ne__(self, other):
+ return not self == other
+
def is_locked(self):
return self.control_files.is_locked()
=== modified file 'bzrlib/smart/client.py'
--- bzrlib/smart/client.py 2007-07-14 15:22:37 +0000
+++ bzrlib/smart/client.py 2007-08-06 01:59:55 +0000
@@ -25,6 +25,12 @@
def __init__(self, shared_medium):
self._shared_medium = shared_medium
+ def __eq__(self, other):
+ return self._shared_medium == other._shared_medium
+
+ def __ne__(self, other):
+ return not self == other
+
def get_smart_medium(self):
return self._shared_medium.connection
=== modified file 'bzrlib/tests/repository_implementations/__init__.py'
--- bzrlib/tests/repository_implementations/__init__.py 2007-07-12 12:07:13 +0000
+++ bzrlib/tests/repository_implementations/__init__.py 2007-08-06 01:59:55 +0000
@@ -91,7 +91,7 @@
return repo
else:
return super(TestCaseWithRepository, self).make_repository(
- relpath, format)
+ relpath, format=format)
=== modified file 'bzrlib/tests/repository_implementations/test_repository.py'
--- bzrlib/tests/repository_implementations/test_repository.py 2007-07-25 00:52:21 +0000
+++ bzrlib/tests/repository_implementations/test_repository.py 2007-08-06 01:59:55 +0000
@@ -422,6 +422,109 @@
self.assertEqual(repo._serializer.format_num, format)
+class TestRepositoryEquality(TestCaseWithRepository):
+
+ def strictAssertEqual(self, a, b):
+ """Like assertEqual, but also checks the `!=` operator is consistent.
+
+ i.e. if `a == b` *and* `a != b`, this method will fail.
+
+ This can happen when a class defines an `__eq__` but doesn't define an
+ `__ne__`.
+ """
+ self.assertEqual(a, b)
+ self.failIf(
+ a != b,
+ "%r and %r are both equal and not equal! Class probably defines "
+ "__eq__ without also defining __ne__." % (a, b))
+
+ def strictAssertNotEqual(self, a, b):
+ """Like assertNotEqual, but also checks the `==` operator is consistent.
+
+ i.e. if `a != b` *and* `a == b`, this method will fail.
+
+ This can happen when a class defines an `__eq__` but doesn't define an
+ `__ne__`.
+
+ :seealso: strictAssertEqual
+ """
+ self.assertNotEqual(a, b)
+ self.failIf(
+ a == b,
+ "%r and %r are both equal and not equal! Class probably defines "
+ "__eq__ without also defining __ne__." % (a, b))
+
+ def test_same_repo_instance_is_equal(self):
+ """A repository object is always equal to itself."""
+ repo = self.make_repository('.')
+ self.strictAssertEqual(repo, repo)
+
+ def test_same_repo_location_is_equal(self):
+ """Different repository objects connected to the same location are
+ equal.
+ """
+ repo = self.make_repository('.')
+ reopened_repo = repo.bzrdir.open_repository()
+ self.failIf(
+ repo is reopened_repo,
+ "This test depends on reopened_repo being a different instance of "
+ "the same repo.")
+ self.strictAssertEqual(repo, reopened_repo)
+
+ def test_different_repos_not_equal(self):
+ """Repositories at different locations are not equal."""
+ repo_one = self.make_repository('one')
+ repo_two = self.make_repository('two')
+ self.strictAssertNotEqual(repo_one, repo_two)
+
+ def test_same_bzrdir_different_control_files_not_equal(self):
+ """Repositories in the same bzrdir, but with different control files,
+ are not equal.
+
+ This can happens e.g. when upgrading a repository. This test mimics how
+ CopyConverter creates a second repository in one bzrdir.
+ """
+ repo = self.make_repository('repo')
+ try:
+ control_transport = repo.control_files._transport
+ except AttributeError:
+ # This test only applies to repository formats with control_files.
+ return
+ if control_transport.base == repo.bzrdir.transport.base:
+ # This test only applies to repository formats where the repo
+ # control_files are separate from other bzrdir files, i.e. metadir
+ # formats.
+ return
+ control_transport.copy_tree('.', '../repository.backup')
+ backup_transport = control_transport.clone('../repository.backup')
+ backup_repo = repo._format.open(repo.bzrdir, _found=True,
+ _override_transport=backup_transport)
+
+ self.strictAssertNotEqual(repo, backup_repo)
+
+ def test_different_format_not_equal(self):
+ """Different format repositories are comparable and not equal.
+
+ Comparing different format repository objects should give a negative
+ result, rather than trigger an exception (which could happen with a
+ naive __eq__ implementation, e.g. due to missing attributes).
+ """
+ repo = self.make_repository('repo')
+ other_repo = self.make_repository('other', format='default')
+ if repo._format == other_repo._format:
+ # We're testing the default format! So we have to use a non-default
+ # format for other_repo.
+ get_transport(self.get_vfs_only_url()).delete_tree('other')
+ other_repo = self.make_repository('other', format='metaweave')
+ # Make sure the other_repo is not a RemoteRepository.
+ other_bzrdir = bzrdir.BzrDir.open(self.get_vfs_only_url('other'))
+ other_repo = other_bzrdir.open_repository()
+ # Compare both ways, to make sure the __eq__ on both repositories cope
+ # with comparing against a different class.
+ self.strictAssertNotEqual(repo, other_repo)
+ self.strictAssertNotEqual(other_repo, repo)
+
+
class TestRepositoryLocking(TestCaseWithRepository):
def test_leave_lock_in_place(self):
# Begin bundle
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
a0qxw5fnsBeAQf/F3JFOFCQgrcjNwA==
More information about the bazaar
mailing list