launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26336
[Merge] ~cjwatson/launchpad:py3-more-hashable into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:py3-more-hashable into launchpad:master.
Commit message:
Make more classes hashable on Python 3
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/398244
Python 3 considers objects unhashable if their class overrides __eq__ but not __hash__, so add suitable __hash__ methods where necessary. I also took the opportunity to remove some __eq__ methods that are now superseded by StormBase.__eq__.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-more-hashable into launchpad:master.
diff --git a/lib/lp/oci/model/ocirecipe.py b/lib/lp/oci/model/ocirecipe.py
index 41493ee..fd76ae6 100644
--- a/lib/lp/oci/model/ocirecipe.py
+++ b/lib/lp/oci/model/ocirecipe.py
@@ -735,3 +735,6 @@ class OCIRecipeBuildRequest:
if not zope_isinstance(other, self.__class__):
return False
return self.id == other.id
+
+ def __hash__(self):
+ return hash((self.__class__, self.id))
diff --git a/lib/lp/oci/model/ocirecipebuild.py b/lib/lp/oci/model/ocirecipebuild.py
index 9163245..9ebb2e0 100644
--- a/lib/lp/oci/model/ocirecipebuild.py
+++ b/lib/lp/oci/model/ocirecipebuild.py
@@ -24,16 +24,12 @@ from storm.locals import (
Or,
Reference,
Store,
- Storm,
Unicode,
)
from storm.store import EmptyResultSet
from zope.component import getUtility
from zope.interface import implementer
-from zope.security.proxy import (
- isinstance as zope_isinstance,
- removeSecurityProxy,
- )
+from zope.security.proxy import removeSecurityProxy
from lp.app.errors import NotFoundError
from lp.buildmaster.enums import (
@@ -71,6 +67,7 @@ from lp.services.database.interfaces import (
IMasterStore,
IStore,
)
+from lp.services.database.stormbase import StormBase
from lp.services.job.interfaces.job import JobStatus
from lp.services.job.model.job import Job
from lp.services.librarian.model import (
@@ -91,7 +88,7 @@ from lp.services.webapp.snapshot import notify_modified
@implementer(IOCIFile)
-class OCIFile(Storm):
+class OCIFile(StormBase):
__storm_table__ = 'OCIFile'
@@ -127,7 +124,7 @@ class OCIFileSet:
@implementer(IOCIRecipeBuild)
-class OCIRecipeBuild(PackageBuildMixin, Storm):
+class OCIRecipeBuild(PackageBuildMixin, StormBase):
__storm_table__ = 'OCIRecipeBuild'
@@ -190,11 +187,6 @@ class OCIRecipeBuild(PackageBuildMixin, Storm):
if build_request is not None:
self.build_request_id = build_request.id
- def __eq__(self, other):
- if not zope_isinstance(other, self.__class__):
- return False
- return self.id == other.id
-
@property
def build_request(self):
"""See `IOCIRecipeBuild`."""
diff --git a/lib/lp/registry/model/persondistributionsourcepackage.py b/lib/lp/registry/model/persondistributionsourcepackage.py
index 8ae9ebb..7dfa6c2 100644
--- a/lib/lp/registry/model/persondistributionsourcepackage.py
+++ b/lib/lp/registry/model/persondistributionsourcepackage.py
@@ -41,8 +41,11 @@ class PersonDistributionSourcePackage:
def __eq__(self, other):
return (
IPersonDistributionSourcePackage.providedBy(other) and
- self.person.id == other.person.id and
+ self.person == other.person and
self.distro_source_package == other.distro_source_package)
def __ne__(self, other):
return not self == other
+
+ def __hash__(self):
+ return hash((self.person, self.distro_source_package))
diff --git a/lib/lp/registry/model/personociproject.py b/lib/lp/registry/model/personociproject.py
index a1137fe..3a1ec86 100644
--- a/lib/lp/registry/model/personociproject.py
+++ b/lib/lp/registry/model/personociproject.py
@@ -39,8 +39,11 @@ class PersonOCIProject:
def __eq__(self, other):
return (
IPersonOCIProject.providedBy(other) and
- self.person.id == other.person.id and
+ self.person == other.person and
self.oci_project == other.oci_project)
def __ne__(self, other):
return not self == other
+
+ def __hash__(self):
+ return hash((self.person, self.oci_project))
diff --git a/lib/lp/registry/model/personproduct.py b/lib/lp/registry/model/personproduct.py
index 16d7ff6..6cade57 100644
--- a/lib/lp/registry/model/personproduct.py
+++ b/lib/lp/registry/model/personproduct.py
@@ -37,12 +37,15 @@ class PersonProduct(HasMergeProposalsMixin):
def __eq__(self, other):
return (
IPersonProduct.providedBy(other) and
- self.person.id == other.person.id and
- self.product.id == other.product.id)
+ self.person == other.person and
+ self.product == other.product)
def __ne__(self, other):
return not self == other
+ def __hash__(self):
+ return hash((self.person, self.product))
+
@property
def private(self):
return self.person.private or self.product.private
diff --git a/lib/lp/registry/model/suitesourcepackage.py b/lib/lp/registry/model/suitesourcepackage.py
index 914da7e..02a99c9 100644
--- a/lib/lp/registry/model/suitesourcepackage.py
+++ b/lib/lp/registry/model/suitesourcepackage.py
@@ -34,6 +34,9 @@ class SuiteSourcePackage:
def __ne__(self, other):
return not (self == other)
+ def __hash__(self):
+ return hash((self.sourcepackage, self.pocket))
+
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, self.path)
diff --git a/lib/lp/services/database/tests/test_collection.py b/lib/lp/services/database/tests/test_collection.py
index f388556..6049ed0 100644
--- a/lib/lp/services/database/tests/test_collection.py
+++ b/lib/lp/services/database/tests/test_collection.py
@@ -5,14 +5,12 @@
__metaclass__ = type
-from storm.locals import (
- Int,
- Storm,
- )
+from storm.locals import Int
from lp.registry.model.person import Person
from lp.services.database.collection import Collection
from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
from lp.testing import TestCaseWithFactory
from lp.testing.fakemethod import FakeMethod
from lp.testing.layers import ZopelessDatabaseLayer
@@ -36,7 +34,7 @@ def make_table(range_start, range_end, table_name=None):
FROM generate_series(%d, %d)
""" % (table_name, range_start, range_end - 1))
- class TestTable(Storm):
+ class TestTable(StormBase):
"""A test class/table generated on the fly for testing purposes."""
__storm_table__ = table_name
id = Int(primary=True)
@@ -45,9 +43,6 @@ def make_table(range_start, range_end, table_name=None):
self.id = id
IStore(self.__class__).add(self)
- def __eq__(self, other):
- return self.id == other.id
-
return TestTable
diff --git a/lib/lp/services/job/runner.py b/lib/lp/services/job/runner.py
index 15ea4e9..4d302d5 100644
--- a/lib/lp/services/job/runner.py
+++ b/lib/lp/services/job/runner.py
@@ -155,6 +155,9 @@ class BaseRunnableJob(BaseRunnableJobSource):
def __ne__(self, job):
return not (self == job)
+ def __hash__(self):
+ return hash(tuple([self.__class__] + sorted(self.__dict__.items())))
+
def __lt__(self, job):
naked_job = removeSecurityProxy(job)
if self.__class__ is naked_job.__class__: