← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:storm-base into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:storm-base into launchpad:master.

Commit message:
Inherit from StormBase instead of directly from Storm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/436687

`lp.services.database.stormbase.StormBase` is described as "A safe version of storm.base.Storm to use in Launchpad", so let's actually use it everywhere.  This will eventually give us a common Launchpad-controlled base class for all our ORM models (though there are currently two, until we get rid of `lp.services.database.sqlbase.SQLBase`).

I looked through https://github.com/DmytroLitvinov/awesome-flake8-extensions for plugins that might help in enforcing this, and `flake8-alfred` seemed to be the best match; this saved me a considerable amount of time searching for imports formatted in various ways.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:storm-base into launchpad:master.
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 643d1e6..1a7a1f4 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -57,6 +57,7 @@ repos:
         exclude: ^lib/contrib/
         additional_dependencies:
           - flake8-absolute-import==1.0.0.1
+          - flake8-alfred==1.1.1
 -   repo: https://github.com/pre-commit/mirrors-eslint
     rev: v8.33.0
     hooks:
diff --git a/lib/lp/archivepublisher/model/publisherconfig.py b/lib/lp/archivepublisher/model/publisherconfig.py
index e5cd108..3842a88 100644
--- a/lib/lp/archivepublisher/model/publisherconfig.py
+++ b/lib/lp/archivepublisher/model/publisherconfig.py
@@ -8,7 +8,7 @@ __all__ = [
     "PublisherConfigSet",
 ]
 
-from storm.locals import Int, Reference, Storm, Unicode
+from storm.locals import Int, Reference, Unicode
 from zope.interface import implementer
 
 from lp.archivepublisher.interfaces.publisherconfig import (
@@ -16,10 +16,11 @@ from lp.archivepublisher.interfaces.publisherconfig import (
     IPublisherConfigSet,
 )
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(IPublisherConfig)
-class PublisherConfig(Storm):
+class PublisherConfig(StormBase):
     """See `IArchiveAuthToken`."""
 
     __storm_table__ = "PublisherConfig"
diff --git a/lib/lp/bugs/model/bugsummary.py b/lib/lp/bugs/model/bugsummary.py
index 9084e0e..4b7d24b 100644
--- a/lib/lp/bugs/model/bugsummary.py
+++ b/lib/lp/bugs/model/bugsummary.py
@@ -9,7 +9,6 @@ __all__ = [
     "get_bugsummary_filter_for_user",
 ]
 
-from storm.base import Storm
 from storm.expr import SQL, And, Or, Select
 from storm.properties import Bool, Int, Unicode
 from storm.references import Reference
@@ -34,11 +33,12 @@ from lp.registry.model.sourcepackagename import SourcePackageName
 from lp.registry.model.teammembership import TeamParticipation
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import WithMaterialized
 
 
 @implementer(IBugSummary)
-class BugSummary(Storm):
+class BugSummary(StormBase):
     """BugSummary Storm database class."""
 
     __storm_table__ = "combinedbugsummary"
diff --git a/lib/lp/bugs/model/bugtarget.py b/lib/lp/bugs/model/bugtarget.py
index 7c2e0c4..2778def 100644
--- a/lib/lp/bugs/model/bugtarget.py
+++ b/lib/lp/bugs/model/bugtarget.py
@@ -10,7 +10,7 @@ __all__ = [
     "OfficialBugTagTargetMixin",
 ]
 
-from storm.locals import Int, Reference, Storm, Unicode
+from storm.locals import Int, Reference, Unicode
 from zope.component import getUtility
 from zope.interface import implementer
 
@@ -26,6 +26,7 @@ from lp.bugs.model.bugtask import BugTaskSet
 from lp.registry.interfaces.distribution import IDistribution
 from lp.registry.interfaces.product import IProduct
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 
 
 class HasBugsBase:
@@ -215,7 +216,7 @@ class OfficialBugTagTargetMixin:
 
 
 @implementer(IOfficialBugTag)
-class OfficialBugTag(Storm):
+class OfficialBugTag(StormBase):
     """See `IOfficialBugTag`."""
 
     # XXX Abel Deuring, 2009-03-11: The SQL table OfficialBugTag has
diff --git a/lib/lp/bugs/model/bugtaskflat.py b/lib/lp/bugs/model/bugtaskflat.py
index b25a440..16ad071 100644
--- a/lib/lp/bugs/model/bugtaskflat.py
+++ b/lib/lp/bugs/model/bugtaskflat.py
@@ -1,7 +1,7 @@
 # Copyright 2012-2020 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from storm.locals import Bool, DateTime, Int, List, Reference, Storm
+from storm.locals import Bool, DateTime, Int, List, Reference
 
 from lp.app.enums import InformationType
 from lp.bugs.interfaces.bugtask import (
@@ -10,9 +10,10 @@ from lp.bugs.interfaces.bugtask import (
     BugTaskStatusSearch,
 )
 from lp.services.database.enumcol import DBEnum
+from lp.services.database.stormbase import StormBase
 
 
-class BugTaskFlat(Storm):
+class BugTaskFlat(StormBase):
 
     __storm_table__ = "BugTaskFlat"
 
diff --git a/lib/lp/bugs/model/structuralsubscription.py b/lib/lp/bugs/model/structuralsubscription.py
index e0409ab..dff0e8f 100644
--- a/lib/lp/bugs/model/structuralsubscription.py
+++ b/lib/lp/bugs/model/structuralsubscription.py
@@ -14,7 +14,6 @@ __all__ = [
 from collections import defaultdict
 
 import pytz
-from storm.base import Storm
 from storm.expr import (
     SQL,
     And,
@@ -72,6 +71,7 @@ from lp.registry.interfaces.sourcepackage import ISourcePackage
 from lp.registry.model.teammembership import TeamParticipation
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import (
     Array,
     ArrayAgg,
@@ -82,7 +82,7 @@ from lp.services.propertycache import cachedproperty
 
 
 @implementer(IStructuralSubscription)
-class StructuralSubscription(Storm):
+class StructuralSubscription(StormBase):
     """A subscription to a Launchpad structure."""
 
     __storm_table__ = "StructuralSubscription"
diff --git a/lib/lp/buildmaster/model/buildfarmjob.py b/lib/lp/buildmaster/model/buildfarmjob.py
index a94c134..14303c4 100644
--- a/lib/lp/buildmaster/model/buildfarmjob.py
+++ b/lib/lp/buildmaster/model/buildfarmjob.py
@@ -12,7 +12,7 @@ import datetime
 
 import pytz
 from storm.expr import Desc, LeftJoin, Or
-from storm.locals import DateTime, Int, Reference, Storm
+from storm.locals import DateTime, Int, Reference
 from storm.store import Store
 from zope.component import getUtility
 from zope.interface import implementer, provider
@@ -29,6 +29,7 @@ from lp.buildmaster.interfaces.buildfarmjob import (
 from lp.buildmaster.model.buildqueue import BuildQueue
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.propertycache import cachedproperty, get_property_cache
 from lp.services.statsd.interfaces.statsd_client import IStatsdClient
 
@@ -53,7 +54,7 @@ VALID_STATUS_TRANSITIONS = {
 
 @implementer(IBuildFarmJob, IBuildFarmJobDB)
 @provider(IBuildFarmJobSource)
-class BuildFarmJob(Storm):
+class BuildFarmJob(StormBase):
     """A base implementation for `IBuildFarmJob` classes."""
 
     __storm_table__ = "BuildFarmJob"
diff --git a/lib/lp/charms/model/charmbase.py b/lib/lp/charms/model/charmbase.py
index 76ef34f..bfff346 100644
--- a/lib/lp/charms/model/charmbase.py
+++ b/lib/lp/charms/model/charmbase.py
@@ -9,7 +9,7 @@ __all__ = [
 
 import pytz
 from storm.databases.postgres import JSON
-from storm.locals import DateTime, Int, Reference, Store, Storm
+from storm.locals import DateTime, Int, Reference, Store
 from zope.interface import implementer
 
 from lp.buildmaster.model.processor import Processor
@@ -21,10 +21,11 @@ from lp.charms.interfaces.charmbase import (
 )
 from lp.services.database.constants import DEFAULT
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(ICharmBase)
-class CharmBase(Storm):
+class CharmBase(StormBase):
     """See `ICharmBase`."""
 
     __storm_table__ = "CharmBase"
@@ -91,7 +92,7 @@ class CharmBase(Storm):
         Store.of(self).remove(self)
 
 
-class CharmBaseArch(Storm):
+class CharmBaseArch(StormBase):
     """Link table to back `CharmBase.processors`."""
 
     __storm_table__ = "CharmBaseArch"
diff --git a/lib/lp/code/model/branchrevision.py b/lib/lp/code/model/branchrevision.py
index 9d0fc80..847f034 100644
--- a/lib/lp/code/model/branchrevision.py
+++ b/lib/lp/code/model/branchrevision.py
@@ -5,14 +5,15 @@ __all__ = [
     "BranchRevision",
 ]
 
-from storm.locals import Int, Reference, Storm
+from storm.locals import Int, Reference
 from zope.interface import implementer
 
 from lp.code.interfaces.branchrevision import IBranchRevision
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(IBranchRevision)
-class BranchRevision(Storm):
+class BranchRevision(StormBase):
     """See `IBranchRevision`."""
 
     __storm_table__ = "BranchRevision"
diff --git a/lib/lp/code/model/diff.py b/lib/lp/code/model/diff.py
index 7def5fd..6f11c56 100644
--- a/lib/lp/code/model/diff.py
+++ b/lib/lp/code/model/diff.py
@@ -23,7 +23,7 @@ from breezy.merge import Merge3Merger
 from breezy.patches import Patch, parse_patches
 from breezy.plugins.difftacular.generate_diff import diff_ignore_branches
 from lazr.delegates import delegate_to
-from storm.locals import Int, Reference, Storm, Unicode
+from storm.locals import Int, Reference, Unicode
 from zope.component import getUtility
 from zope.error.interfaces import IErrorReportingUtility
 from zope.interface import implementer
@@ -37,6 +37,7 @@ from lp.services.database.constants import UTC_NOW
 from lp.services.database.datetimecol import UtcDateTimeCol
 from lp.services.database.sqlbase import SQLBase
 from lp.services.database.sqlobject import ForeignKey, IntCol, StringCol
+from lp.services.database.stormbase import StormBase
 from lp.services.librarian.interfaces import ILibraryFileAliasSet
 from lp.services.librarian.interfaces.client import (
     LIBRARIAN_SERVER_DEFAULT_TIMEOUT,
@@ -335,7 +336,7 @@ class Diff(SQLBase):
 
 @implementer(IIncrementalDiff)
 @delegate_to(IDiff, context="diff")
-class IncrementalDiff(Storm):
+class IncrementalDiff(StormBase):
     """See `IIncrementalDiff."""
 
     __storm_table__ = "IncrementalDiff"
@@ -365,7 +366,7 @@ class IncrementalDiff(Storm):
 
 @implementer(IPreviewDiff)
 @delegate_to(IDiff, context="diff")
-class PreviewDiff(Storm):
+class PreviewDiff(StormBase):
     """See `IPreviewDiff`."""
 
     __storm_table__ = "PreviewDiff"
diff --git a/lib/lp/code/model/revision.py b/lib/lp/code/model/revision.py
index 9d1a631..96b4320 100644
--- a/lib/lp/code/model/revision.py
+++ b/lib/lp/code/model/revision.py
@@ -24,7 +24,6 @@ from storm.locals import (
     Min,
     Reference,
     ReferenceSet,
-    Storm,
     Unicode,
 )
 from storm.store import Store
@@ -713,7 +712,7 @@ def revision_time_limit(day_limit):
     )
 
 
-class RevisionCache(Storm):
+class RevisionCache(StormBase):
     """A cached version of a recent revision."""
 
     __storm_table__ = "RevisionCache"
diff --git a/lib/lp/code/model/seriessourcepackagebranch.py b/lib/lp/code/model/seriessourcepackagebranch.py
index 110df7d..da5327a 100644
--- a/lib/lp/code/model/seriessourcepackagebranch.py
+++ b/lib/lp/code/model/seriessourcepackagebranch.py
@@ -11,7 +11,7 @@ __all__ = [
 from datetime import datetime
 
 import pytz
-from storm.locals import DateTime, Int, Reference, Storm
+from storm.locals import DateTime, Int, Reference
 from zope.interface import implementer
 
 from lp.code.interfaces.seriessourcepackagebranch import (
@@ -21,10 +21,11 @@ from lp.code.interfaces.seriessourcepackagebranch import (
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(ISeriesSourcePackageBranch)
-class SeriesSourcePackageBranch(Storm):
+class SeriesSourcePackageBranch(StormBase):
     """See `ISeriesSourcePackageBranch`."""
 
     __storm_table__ = "SeriesSourcePackageBranch"
diff --git a/lib/lp/code/model/sourcepackagerecipe.py b/lib/lp/code/model/sourcepackagerecipe.py
index 38ea8f6..de53ee2 100644
--- a/lib/lp/code/model/sourcepackagerecipe.py
+++ b/lib/lp/code/model/sourcepackagerecipe.py
@@ -21,7 +21,6 @@ from storm.locals import (
     Reference,
     ReferenceSet,
     Store,
-    Storm,
     Unicode,
 )
 from zope.component import getUtility
@@ -48,6 +47,7 @@ from lp.services.database.bulk import load_referencing
 from lp.services.database.constants import DEFAULT, UTC_NOW
 from lp.services.database.datetimecol import UtcDateTimeCol
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import Greatest, NullsLast
 from lp.services.propertycache import cachedproperty, get_property_cache
 from lp.soyuz.model.archive import Archive
@@ -67,7 +67,7 @@ class NonPPABuildRequest(Exception):
     unsupported."""
 
 
-class _SourcePackageRecipeDistroSeries(Storm):
+class _SourcePackageRecipeDistroSeries(StormBase):
     """Link table for many-to-many relationship."""
 
     __storm_table__ = "SourcePackageRecipeDistroSeries"
@@ -83,7 +83,7 @@ class _SourcePackageRecipeDistroSeries(Storm):
 @implementer(ISourcePackageRecipe)
 @provider(ISourcePackageRecipeSource)
 @delegate_to(ISourcePackageRecipeData, context="_recipe_data")
-class SourcePackageRecipe(Storm):
+class SourcePackageRecipe(StormBase):
     """See `ISourcePackageRecipe` and `ISourcePackageRecipeSource`."""
 
     __storm_table__ = "SourcePackageRecipe"
diff --git a/lib/lp/code/model/sourcepackagerecipebuild.py b/lib/lp/code/model/sourcepackagerecipebuild.py
index 11d0658..eb600f6 100644
--- a/lib/lp/code/model/sourcepackagerecipebuild.py
+++ b/lib/lp/code/model/sourcepackagerecipebuild.py
@@ -12,7 +12,7 @@ from datetime import timedelta
 
 import pytz
 from psycopg2 import ProgrammingError
-from storm.locals import Bool, DateTime, Int, Reference, Storm, Unicode
+from storm.locals import Bool, DateTime, Int, Reference, Unicode
 from storm.store import EmptyResultSet, Store
 from zope.component import getUtility
 from zope.interface import implementer, provider
@@ -44,6 +44,7 @@ from lp.services.database.constants import UTC_NOW
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.librarian.browser import ProxiedLibraryFileAlias
 from lp.soyuz.interfaces.archive import CannotUploadToArchive
 from lp.soyuz.model.archive import Archive
@@ -54,7 +55,7 @@ from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
 @implementer(ISourcePackageRecipeBuild)
 @provider(ISourcePackageRecipeBuildSource)
 class SourcePackageRecipeBuild(
-    SpecificBuildFarmJobSourceMixin, PackageBuildMixin, Storm
+    SpecificBuildFarmJobSourceMixin, PackageBuildMixin, StormBase
 ):
 
     __storm_table__ = "SourcePackageRecipeBuild"
diff --git a/lib/lp/code/model/sourcepackagerecipedata.py b/lib/lp/code/model/sourcepackagerecipedata.py
index 9823360..ae00b03 100644
--- a/lib/lp/code/model/sourcepackagerecipedata.py
+++ b/lib/lp/code/model/sourcepackagerecipedata.py
@@ -33,7 +33,6 @@ from storm.locals import (
     ReferenceSet,
     Select,
     Store,
-    Storm,
     Unicode,
 )
 from zope.component import getUtility
@@ -62,6 +61,7 @@ from lp.code.model.gitrepository import GitRepository
 from lp.services.database.bulk import load_referencing, load_related
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.propertycache import (
     cachedproperty,
     clear_property_cache,
@@ -97,7 +97,7 @@ class InstructionType(DBEnumeratedType):
     )
 
 
-class _SourcePackageRecipeDataInstruction(Storm):
+class _SourcePackageRecipeDataInstruction(StormBase):
     """A single line from a recipe."""
 
     __storm_table__ = "SourcePackageRecipeDataInstruction"
@@ -192,7 +192,7 @@ MAX_RECIPE_FORMAT = 0.4
 
 @implementer(ISourcePackageRecipeData)
 @provider(IRecipeBranchSource, ISourcePackageRecipeDataSource)
-class SourcePackageRecipeData(Storm):
+class SourcePackageRecipeData(StormBase):
     """The database representation of a BaseRecipeBranch from bzr-builder.
 
     This is referenced from the SourcePackageRecipe table as the 'recipe_data'
diff --git a/lib/lp/oci/browser/tests/test_ocirecipe.py b/lib/lp/oci/browser/tests/test_ocirecipe.py
index 56d61f5..19e2bf4 100644
--- a/lib/lp/oci/browser/tests/test_ocirecipe.py
+++ b/lib/lp/oci/browser/tests/test_ocirecipe.py
@@ -2571,17 +2571,18 @@ class TestOCIRecipeEditPushRulesView(
             registry_credentials=registry_credentials,
             image_name=image_name,
         )
+        push_rule_id = push_rule.id
         browser = self.getViewBrowser(self.recipe, user=self.person)
         browser.getLink("Edit push rules").click()
         with person_logged_in(self.person):
             browser.getControl(
-                name="field.delete.%d" % push_rule.id
+                name="field.delete.%d" % push_rule_id
             ).value = True
         browser.getControl("Save").click()
 
         with person_logged_in(self.person):
             self.assertIsNone(
-                getUtility(IOCIPushRuleSet).getByID(push_rule.id)
+                getUtility(IOCIPushRuleSet).getByID(push_rule_id)
             )
 
     def test_add_oci_push_rules_validations(self):
diff --git a/lib/lp/oci/model/ocipushrule.py b/lib/lp/oci/model/ocipushrule.py
index 483946a..2d6ca6a 100644
--- a/lib/lp/oci/model/ocipushrule.py
+++ b/lib/lp/oci/model/ocipushrule.py
@@ -9,7 +9,7 @@ __all__ = [
     "OCIPushRuleSet",
 ]
 
-from storm.locals import Int, Reference, Storm, Unicode
+from storm.locals import Int, Reference, Unicode
 from zope.interface import implementer
 
 from lp.oci.interfaces.ocipushrule import (
@@ -18,10 +18,11 @@ from lp.oci.interfaces.ocipushrule import (
     OCIPushRuleAlreadyExists,
 )
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(IOCIPushRule)
-class OCIPushRule(Storm):
+class OCIPushRule(StormBase):
 
     __storm_table__ = "OCIPushRule"
 
diff --git a/lib/lp/oci/model/ocirecipe.py b/lib/lp/oci/model/ocirecipe.py
index ed46c81..23bf584 100644
--- a/lib/lp/oci/model/ocirecipe.py
+++ b/lib/lp/oci/model/ocirecipe.py
@@ -17,7 +17,7 @@ import pytz
 from lazr.lifecycle.event import ObjectCreatedEvent
 from storm.databases.postgres import JSON
 from storm.expr import SQL, And, Coalesce, Desc, Exists, Join, Not, Or, Select
-from storm.locals import Bool, DateTime, Int, Reference, Store, Storm, Unicode
+from storm.locals import Bool, DateTime, Int, Reference, Store, Unicode
 from zope.component import getAdapter, getUtility
 from zope.event import notify
 from zope.interface import implementer
@@ -95,6 +95,7 @@ from lp.services.database.constants import DEFAULT, UTC_NOW
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import (
     Array,
     ArrayAgg,
@@ -121,7 +122,7 @@ def oci_recipe_modified(recipe, event):
 
 
 @implementer(IOCIRecipe)
-class OCIRecipe(Storm, WebhookTargetMixin):
+class OCIRecipe(StormBase, WebhookTargetMixin):
 
     __storm_table__ = "OCIRecipe"
 
@@ -866,7 +867,7 @@ class OCIRecipe(Storm, WebhookTargetMixin):
         return push_rule
 
 
-class OCIRecipeArch(Storm):
+class OCIRecipeArch(StormBase):
     """Link table to back `OCIRecipe.processors`."""
 
     __storm_table__ = "OCIRecipeArch"
diff --git a/lib/lp/oci/model/ociregistrycredentials.py b/lib/lp/oci/model/ociregistrycredentials.py
index 2a6684e..c31e995 100644
--- a/lib/lp/oci/model/ociregistrycredentials.py
+++ b/lib/lp/oci/model/ociregistrycredentials.py
@@ -12,7 +12,7 @@ import base64
 import json
 
 from storm.databases.postgres import JSON
-from storm.locals import Int, Reference, Storm, Unicode
+from storm.locals import Int, Reference, Unicode
 from zope.component import getUtility
 from zope.interface import implementer
 from zope.schema import ValidationError
@@ -29,6 +29,7 @@ from lp.services.config import config
 from lp.services.crypto.interfaces import CryptoError, IEncryptedContainer
 from lp.services.crypto.model import NaClEncryptedContainerBase
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(IEncryptedContainer)
@@ -64,7 +65,7 @@ def url_validator(allowed_schemes):
 
 
 @implementer(IOCIRegistryCredentials)
-class OCIRegistryCredentials(Storm):
+class OCIRegistryCredentials(StormBase):
 
     __storm_table__ = "OCIRegistryCredentials"
 
diff --git a/lib/lp/registry/browser/tests/test_distribution_views.py b/lib/lp/registry/browser/tests/test_distribution_views.py
index d73497d..0855c49 100644
--- a/lib/lp/registry/browser/tests/test_distribution_views.py
+++ b/lib/lp/registry/browser/tests/test_distribution_views.py
@@ -522,6 +522,7 @@ class TestDistroEditView(OCIConfigHelperMixin, TestCaseWithFactory):
         credentials = self.factory.makeOCIRegistryCredentials(
             registrant=self.distribution.owner, owner=self.distribution.owner
         )
+        credentials_id = credentials.id
         self.distribution.oci_registry_credentials = credentials
         registry_url = self.factory.getUniqueURL()
         edit_form["field.oci_registry_credentials.url"] = registry_url
@@ -543,7 +544,7 @@ class TestDistroEditView(OCIConfigHelperMixin, TestCaseWithFactory):
         )
         # This should have created new records
         self.assertNotEqual(
-            credentials.id, self.distribution.oci_registry_credentials.id
+            credentials_id, self.distribution.oci_registry_credentials.id
         )
 
     def test_oci_create_credentials_change_password(self):
@@ -551,10 +552,11 @@ class TestDistroEditView(OCIConfigHelperMixin, TestCaseWithFactory):
         credentials = self.factory.makeOCIRegistryCredentials(
             registrant=self.distribution.owner, owner=self.distribution.owner
         )
+        url = credentials.url
         self.distribution.oci_registry_credentials = credentials
         transaction.commit()
         password = self.factory.getUniqueUnicode()
-        edit_form["field.oci_registry_credentials.url"] = credentials.url
+        edit_form["field.oci_registry_credentials.url"] = url
         edit_form[
             "field.oci_registry_credentials.username"
         ] = credentials.username
@@ -574,7 +576,7 @@ class TestDistroEditView(OCIConfigHelperMixin, TestCaseWithFactory):
         unencrypted_credentials = distro_credentials.getCredentials()
         self.assertEqual(password, unencrypted_credentials["password"])
         # This should not have changed
-        self.assertEqual(distro_credentials.url, credentials.url)
+        self.assertEqual(url, distro_credentials.url)
 
     def test_oci_delete_credentials(self):
         edit_form = self.getDefaultEditDict()
diff --git a/lib/lp/registry/model/distributionsourcepackage.py b/lib/lp/registry/model/distributionsourcepackage.py
index 76d68db..5daba67 100644
--- a/lib/lp/registry/model/distributionsourcepackage.py
+++ b/lib/lp/registry/model/distributionsourcepackage.py
@@ -16,7 +16,7 @@ import six
 import transaction
 from breezy.lru_cache import LRUCache
 from storm.expr import And, Cast, Desc
-from storm.locals import SQL, Bool, Int, Not, Reference, Store, Storm, Unicode
+from storm.locals import SQL, Bool, Int, Not, Reference, Store, Unicode
 from zope.interface import implementer
 
 from lp.bugs.interfaces.bugsummary import IBugSummaryDimension
@@ -44,6 +44,7 @@ from lp.registry.model.sourcepackage import (
 from lp.services.database.bulk import load
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.propertycache import cachedproperty
 from lp.soyuz.enums import ArchivePurpose, PackagePublishingStatus
 from lp.soyuz.model.archive import Archive
@@ -576,7 +577,7 @@ class ThreadLocalLRUCache(LRUCache, local):
         self.clear()
 
 
-class DistributionSourcePackageInDatabase(Storm):
+class DistributionSourcePackageInDatabase(StormBase):
     """Temporary class to allow access to the database."""
 
     # XXX: allenap 2008-11-13 bug=297736: This is a temporary measure
diff --git a/lib/lp/registry/model/distroseriesdifferencecomment.py b/lib/lp/registry/model/distroseriesdifferencecomment.py
index d882fa0..c9c3e69 100644
--- a/lib/lp/registry/model/distroseriesdifferencecomment.py
+++ b/lib/lp/registry/model/distroseriesdifferencecomment.py
@@ -9,7 +9,7 @@ __all__ = [
 
 from email.utils import make_msgid
 
-from storm.locals import Desc, Int, Reference, Storm
+from storm.locals import Desc, Int, Reference
 from zope.interface import implementer, provider
 
 from lp.registry.interfaces.distroseriesdifferencecomment import (
@@ -18,12 +18,13 @@ from lp.registry.interfaces.distroseriesdifferencecomment import (
 )
 from lp.registry.model.sourcepackagename import SourcePackageName
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.messages.model.message import Message, MessageChunk
 
 
 @implementer(IDistroSeriesDifferenceComment)
 @provider(IDistroSeriesDifferenceCommentSource)
-class DistroSeriesDifferenceComment(Storm):
+class DistroSeriesDifferenceComment(StormBase):
     """See `IDistroSeriesDifferenceComment`."""
 
     __storm_table__ = "DistroSeriesDifferenceMessage"
diff --git a/lib/lp/registry/model/distroseriesparent.py b/lib/lp/registry/model/distroseriesparent.py
index 94adc35..89ed55f 100644
--- a/lib/lp/registry/model/distroseriesparent.py
+++ b/lib/lp/registry/model/distroseriesparent.py
@@ -8,7 +8,7 @@ __all__ = [
     "DistroSeriesParentSet",
 ]
 
-from storm.locals import SQL, Bool, Int, Reference, Storm
+from storm.locals import SQL, Bool, Int, Reference
 from zope.interface import implementer
 
 from lp.registry.interfaces.distroseriesparent import (
@@ -18,10 +18,11 @@ from lp.registry.interfaces.distroseriesparent import (
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(IDistroSeriesParent)
-class DistroSeriesParent(Storm):
+class DistroSeriesParent(StormBase):
     """See `IDistroSeriesParent`."""
 
     __storm_table__ = "DistroSeriesParent"
diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
index 175ccfc..6f9d7ee 100644
--- a/lib/lp/registry/model/person.py
+++ b/lib/lp/registry/model/person.py
@@ -41,7 +41,6 @@ import transaction
 from lazr.delegates import delegate_to
 from lazr.restful.utils import get_current_browser_request, smartquote
 from requests import PreparedRequest
-from storm.base import Storm
 from storm.expr import (
     SQL,
     Alias,
@@ -354,7 +353,7 @@ def person_sort_key(person):
 
 
 @implementer(IPersonSettings)
-class PersonSettings(Storm):
+class PersonSettings(StormBase):
     "The relatively rarely used settings for person (not a team)."
 
     __storm_table__ = "PersonSettings"
diff --git a/lib/lp/scripts/tests/test_garbo.py b/lib/lp/scripts/tests/test_garbo.py
index 1d22660..dce4882 100644
--- a/lib/lp/scripts/tests/test_garbo.py
+++ b/lib/lp/scripts/tests/test_garbo.py
@@ -20,7 +20,7 @@ from psycopg2 import IntegrityError
 from pytz import UTC
 from storm.exceptions import LostObjectError
 from storm.expr import SQL, In, Min, Not
-from storm.locals import Int, Storm
+from storm.locals import Int
 from storm.store import Store
 from testtools.content import text_content
 from testtools.matchers import (
@@ -95,6 +95,7 @@ from lp.services.database.constants import (
     UTC_NOW,
 )
 from lp.services.database.interfaces import IPrimaryStore
+from lp.services.database.stormbase import StormBase
 from lp.services.features.model import FeatureFlag
 from lp.services.features.testing import FeatureFixture
 from lp.services.identity.interfaces.account import AccountStatus
@@ -175,7 +176,7 @@ class TestGarboScript(TestCase):
         DatabaseLayer.force_dirty_database()
 
 
-class BulkFoo(Storm):
+class BulkFoo(StormBase):
     __storm_table__ = "bulkfoo"
     id = Int(primary=True)
 
diff --git a/lib/lp/services/apachelogparser/model/parsedapachelog.py b/lib/lp/services/apachelogparser/model/parsedapachelog.py
index 0afc4c1..66a4b35 100644
--- a/lib/lp/services/apachelogparser/model/parsedapachelog.py
+++ b/lib/lp/services/apachelogparser/model/parsedapachelog.py
@@ -4,7 +4,7 @@
 __all__ = ["ParsedApacheLog"]
 
 import six
-from storm.locals import Int, Storm, Unicode
+from storm.locals import Int, Unicode
 from zope.interface import implementer
 
 from lp.services.apachelogparser.interfaces.parsedapachelog import (
@@ -13,10 +13,11 @@ from lp.services.apachelogparser.interfaces.parsedapachelog import (
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.datetimecol import UtcDateTimeCol
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(IParsedApacheLog)
-class ParsedApacheLog(Storm):
+class ParsedApacheLog(StormBase):
     """See `IParsedApacheLog`"""
 
     __storm_table__ = "ParsedApacheLog"
diff --git a/lib/lp/services/database/sqlbase.py b/lib/lp/services/database/sqlbase.py
index 419b0c7..ba70a7d 100644
--- a/lib/lp/services/database/sqlbase.py
+++ b/lib/lp/services/database/sqlbase.py
@@ -42,7 +42,8 @@ from psycopg2.extensions import (
 from storm.databases.postgres import compile as postgres_compile
 from storm.expr import State
 from storm.expr import compile as storm_compile
-from storm.locals import Store, Storm
+from storm.locals import Storm  # noqa: B1
+from storm.locals import Store
 from storm.zope.interfaces import IZStorm
 from twisted.python.util import mergeFunctionMetadata
 from zope.component import getUtility
@@ -186,7 +187,7 @@ class SQLBase(storm.sqlobject.SQLObjectBase):
         # some_person.account = an_account fail?
         for key, argument in kwargs.items():
             argument = removeSecurityProxy(argument)
-            if not isinstance(argument, Storm):
+            if not isinstance(argument, Storm):  # noqa: B1
                 continue
             argument_store = Store.of(argument)
             if argument_store is not store:
diff --git a/lib/lp/services/database/stormbase.py b/lib/lp/services/database/stormbase.py
index 2bd27a3..1268501 100644
--- a/lib/lp/services/database/stormbase.py
+++ b/lib/lp/services/database/stormbase.py
@@ -6,14 +6,14 @@ __all__ = [
 ]
 
 from storm.info import get_obj_info
-from storm.locals import Storm
+from storm.locals import Storm  # noqa: B1
 from zope.security.proxy import removeSecurityProxy
 
 from lp.services.database.interfaces import IStore
 from lp.services.propertycache import clear_property_cache
 
 
-class StormBase(Storm):
+class StormBase(Storm):  # noqa: B1
     """A safe version of storm.base.Storm to use in launchpad.
 
     This class adds storm cache management functions to base.Storm.
diff --git a/lib/lp/services/features/model.py b/lib/lp/services/features/model.py
index e7206b7..f869499 100644
--- a/lib/lp/services/features/model.py
+++ b/lib/lp/services/features/model.py
@@ -11,11 +11,12 @@ from datetime import datetime
 
 import pytz
 import six
-from storm.locals import DateTime, Int, Reference, Storm, Unicode
+from storm.locals import DateTime, Int, Reference, Unicode
 from zope.interface import implementer
 
 from lp.services.database.datetimecol import UtcDateTimeCol
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.features.interfaces import IFeatureRules
 
 
@@ -28,7 +29,7 @@ class FeatureRules:
     pass
 
 
-class FeatureFlag(Storm):
+class FeatureFlag(StormBase):
     """Database setting of a particular flag in a scope"""
 
     __storm_table__ = "FeatureFlag"
@@ -48,7 +49,7 @@ class FeatureFlag(Storm):
         self.value = value
 
 
-class FeatureFlagChangelogEntry(Storm):
+class FeatureFlagChangelogEntry(StormBase):
     """A record of a change to the whole set of feature flags."""
 
     __storm_table__ = "FeatureFlagChangelogEntry"
diff --git a/lib/lp/services/messages/model/message.py b/lib/lp/services/messages/model/message.py
index cb9e9cf..21f8bc9 100644
--- a/lib/lp/services/messages/model/message.py
+++ b/lib/lp/services/messages/model/message.py
@@ -29,7 +29,6 @@ from storm.locals import (
     Reference,
     ReferenceSet,
     Store,
-    Storm,
     Unicode,
 )
 from zope.component import getUtility
@@ -54,6 +53,7 @@ from lp.services.database.sqlobject import (
     SQLRelatedJoin,
     StringCol,
 )
+from lp.services.database.stormbase import StormBase
 from lp.services.librarian.interfaces import ILibraryFileAliasSet
 from lp.services.messages.interfaces.message import (
     IDirectEmailAuthorization,
@@ -648,7 +648,7 @@ class MessageChunk(SQLBase):
 
 
 @implementer(IUserToUserEmail)
-class UserToUserEmail(Storm):
+class UserToUserEmail(StormBase):
     """See `IUserToUserEmail`."""
 
     __storm_table__ = "UserToUserEmail"
diff --git a/lib/lp/services/openid/model/openididentifier.py b/lib/lp/services/openid/model/openididentifier.py
index 16d0d63..18ef165 100644
--- a/lib/lp/services/openid/model/openididentifier.py
+++ b/lib/lp/services/openid/model/openididentifier.py
@@ -5,13 +5,14 @@
 
 __all__ = ["OpenIdIdentifier"]
 
-from storm.locals import Int, Reference, Storm, Unicode
+from storm.locals import Int, Reference, Unicode
 
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.datetimecol import UtcDateTimeCol
+from lp.services.database.stormbase import StormBase
 
 
-class OpenIdIdentifier(Storm):
+class OpenIdIdentifier(StormBase):
     """An OpenId Identifier that can be used to log into an Account"""
 
     __storm_table__ = "openididentifier"
diff --git a/lib/lp/services/session/model.py b/lib/lp/services/session/model.py
index 565e1ee..b54d290 100644
--- a/lib/lp/services/session/model.py
+++ b/lib/lp/services/session/model.py
@@ -5,16 +5,17 @@
 
 __all__ = ["SessionData", "SessionPkgData"]
 
-from storm.locals import Pickle, Storm, Unicode
+from storm.locals import Pickle, Unicode
 from zope.interface import implementer, provider
 
 from lp.services.database.datetimecol import UtcDateTimeCol
+from lp.services.database.stormbase import StormBase
 from lp.services.session.interfaces import IUseSessionStore
 
 
 @implementer(IUseSessionStore)
 @provider(IUseSessionStore)
-class SessionData(Storm):
+class SessionData(StormBase):
     """A user's Session."""
 
     __storm_table__ = "SessionData"
@@ -25,7 +26,7 @@ class SessionData(Storm):
 
 @implementer(IUseSessionStore)
 @provider(IUseSessionStore)
-class SessionPkgData(Storm):
+class SessionPkgData(StormBase):
     """Data storage for a Session."""
 
     __storm_table__ = "SessionPkgData"
diff --git a/lib/lp/services/webapp/vocabulary.py b/lib/lp/services/webapp/vocabulary.py
index 1d965a2..7357739 100644
--- a/lib/lp/services/webapp/vocabulary.py
+++ b/lib/lp/services/webapp/vocabulary.py
@@ -25,7 +25,7 @@ from collections import namedtuple
 from typing import Optional, Union
 
 import six
-from storm.base import Storm
+from storm.base import Storm  # noqa: B1
 from storm.expr import Expr
 from storm.store import EmptyResultSet
 from zope.interface import Attribute, Interface, implementer
@@ -489,7 +489,7 @@ class StormVocabularyBase(FilteredVocabularyBase):
         # Sometimes this method is called with a Storm instance, but z3 form
         # machinery sends through integer ids.  This might be due to a bug
         # somewhere.
-        if zisinstance(obj, Storm):
+        if zisinstance(obj, Storm):  # noqa: B1
             clauses = [self._table.id == obj.id]
             if self._clauses:
                 # XXX kiko 2007-01-16: this code is untested.
@@ -507,7 +507,7 @@ class StormVocabularyBase(FilteredVocabularyBase):
     def getTerm(self, value):
         # Short circuit.  There is probably a design problem here since we
         # sometimes get the id and sometimes a Storm instance.
-        if zisinstance(value, Storm):
+        if zisinstance(value, Storm):  # noqa: B1
             return self.toTerm(value)
 
         try:
@@ -584,7 +584,7 @@ class NamedStormVocabulary(StormVocabularyBase):
             return SimpleTerm(obj, obj.name, obj.title)
 
     def __contains__(self, obj):
-        if zisinstance(obj, Storm):
+        if zisinstance(obj, Storm):  # noqa: B1
             found_obj = (
                 IStore(self._table)
                 .find(
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index 6bbcf8f..de5e86e 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -31,16 +31,7 @@ from storm.expr import (
     Or,
     Select,
 )
-from storm.locals import (
-    JSON,
-    Bool,
-    DateTime,
-    Int,
-    Reference,
-    Store,
-    Storm,
-    Unicode,
-)
+from storm.locals import JSON, Bool, DateTime, Int, Reference, Store, Unicode
 from zope.component import getAdapter, getUtility
 from zope.event import notify
 from zope.interface import directlyProvides, implementer
@@ -124,6 +115,7 @@ from lp.services.database.constants import DEFAULT, UTC_NOW
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import (
     Array,
     ArrayAgg,
@@ -288,7 +280,7 @@ class SnapBuildRequest:
 
 
 @implementer(ISnap, IHasOwner)
-class Snap(Storm, WebhookTargetMixin):
+class Snap(StormBase, WebhookTargetMixin):
     """See `ISnap`."""
 
     __storm_table__ = "Snap"
@@ -1481,7 +1473,7 @@ class Snap(Storm, WebhookTargetMixin):
         ).remove()
 
 
-class SnapArch(Storm):
+class SnapArch(StormBase):
     """Link table to back `Snap.processors`."""
 
     __storm_table__ = "SnapArch"
diff --git a/lib/lp/snappy/model/snapbase.py b/lib/lp/snappy/model/snapbase.py
index c8c200d..779ba4b 100644
--- a/lib/lp/snappy/model/snapbase.py
+++ b/lib/lp/snappy/model/snapbase.py
@@ -12,16 +12,7 @@ from typing import Dict, Optional
 import pytz
 from lazr.enum import Item
 from storm.databases.postgres import JSON as PgJSON
-from storm.locals import (
-    JSON,
-    Bool,
-    DateTime,
-    Int,
-    Reference,
-    Store,
-    Storm,
-    Unicode,
-)
+from storm.locals import JSON, Bool, DateTime, Int, Reference, Store, Unicode
 from zope.component import getUtility
 from zope.interface import implementer
 from zope.security.proxy import removeSecurityProxy
@@ -32,6 +23,7 @@ from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.model.person import Person
 from lp.services.database.constants import DEFAULT
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.snappy.interfaces.snapbase import (
     CannotDeleteSnapBase,
     ISnapBase,
@@ -49,7 +41,7 @@ from lp.soyuz.model.archivedependency import ArchiveDependency
 
 
 @implementer(ISnapBase)
-class SnapBase(Storm):
+class SnapBase(StormBase):
     """See `ISnapBase`."""
 
     __storm_table__ = "SnapBase"
@@ -222,7 +214,7 @@ class SnapBase(Storm):
         Store.of(self).remove(self)
 
 
-class SnapBaseArch(Storm):
+class SnapBaseArch(StormBase):
     """Link table to back `SnapArch.processors`."""
 
     __storm_table__ = "SnapBaseArch"
diff --git a/lib/lp/snappy/model/snapbuild.py b/lib/lp/snappy/model/snapbuild.py
index 2ae196c..410942b 100644
--- a/lib/lp/snappy/model/snapbuild.py
+++ b/lib/lp/snappy/model/snapbuild.py
@@ -25,7 +25,6 @@ from storm.locals import (
     Reference,
     Select,
     Store,
-    Storm,
     Unicode,
 )
 from storm.store import EmptyResultSet
@@ -57,6 +56,7 @@ from lp.services.database.constants import DEFAULT
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, 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.browser import ProxiedLibraryFileAlias
@@ -94,7 +94,7 @@ class SnapBuildStatusChangedEvent(ObjectEvent):
 
 
 @implementer(ISnapFile)
-class SnapFile(Storm):
+class SnapFile(StormBase):
     """See `ISnap`."""
 
     __storm_table__ = "SnapFile"
@@ -115,7 +115,7 @@ class SnapFile(Storm):
 
 
 @implementer(ISnapBuild)
-class SnapBuild(PackageBuildMixin, Storm):
+class SnapBuild(PackageBuildMixin, StormBase):
     """See `ISnapBuild`."""
 
     __storm_table__ = "SnapBuild"
diff --git a/lib/lp/snappy/model/snappyseries.py b/lib/lp/snappy/model/snappyseries.py
index fec61f1..5a74579 100644
--- a/lib/lp/snappy/model/snappyseries.py
+++ b/lib/lp/snappy/model/snappyseries.py
@@ -10,16 +10,7 @@ __all__ = [
 ]
 
 import pytz
-from storm.locals import (
-    Bool,
-    DateTime,
-    Desc,
-    Int,
-    Reference,
-    Store,
-    Storm,
-    Unicode,
-)
+from storm.locals import Bool, DateTime, Desc, Int, Reference, Store, Unicode
 from zope.interface import implementer
 
 from lp.registry.interfaces.series import SeriesStatus
@@ -27,6 +18,7 @@ from lp.registry.model.distroseries import DistroSeries
 from lp.services.database.constants import DEFAULT
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.propertycache import cachedproperty, get_property_cache
 from lp.snappy.interfaces.snappyseries import (
     ISnappyDistroSeries,
@@ -38,7 +30,7 @@ from lp.snappy.interfaces.snappyseries import (
 
 
 @implementer(ISnappySeries)
-class SnappySeries(Storm):
+class SnappySeries(StormBase):
     """See `ISnappySeries`."""
 
     __storm_table__ = "SnappySeries"
@@ -220,7 +212,7 @@ class SnappyDistroSeriesMixin:
 
 
 @implementer(ISnappyDistroSeries)
-class SnappyDistroSeries(Storm, SnappyDistroSeriesMixin):
+class SnappyDistroSeries(StormBase, SnappyDistroSeriesMixin):
     """Link table between `SnappySeries` and `DistroSeries`."""
 
     __storm_table__ = "SnappyDistroSeries"
diff --git a/lib/lp/soyuz/model/archive.py b/lib/lp/soyuz/model/archive.py
index b74321f..3eb9387 100644
--- a/lib/lp/soyuz/model/archive.py
+++ b/lib/lp/soyuz/model/archive.py
@@ -18,7 +18,6 @@ from pathlib import PurePath
 
 import six
 from lazr.lifecycle.event import ObjectCreatedEvent
-from storm.base import Storm
 from storm.expr import (
     And,
     Cast,
@@ -91,6 +90,7 @@ from lp.services.database.sqlobject import (
     IntCol,
     StringCol,
 )
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import BulkUpdate
 from lp.services.features import getFeatureFlag
 from lp.services.gpg.interfaces import IGPGHandler
@@ -3795,7 +3795,7 @@ class ArchiveSet:
         return []
 
 
-class ArchiveArch(Storm):
+class ArchiveArch(StormBase):
     """Link table to back Archive.processors."""
 
     __storm_table__ = "ArchiveArch"
diff --git a/lib/lp/soyuz/model/archiveauthtoken.py b/lib/lp/soyuz/model/archiveauthtoken.py
index e9726a3..6f20ce5 100644
--- a/lib/lp/soyuz/model/archiveauthtoken.py
+++ b/lib/lp/soyuz/model/archiveauthtoken.py
@@ -10,22 +10,14 @@ __all__ = [
 import pytz
 from lazr.uri import URI
 from storm.expr import LeftJoin
-from storm.locals import (
-    And,
-    DateTime,
-    Int,
-    Join,
-    Or,
-    Reference,
-    Storm,
-    Unicode,
-)
+from storm.locals import And, DateTime, Int, Join, Or, Reference, Unicode
 from storm.store import Store
 from zope.interface import implementer
 
 from lp.registry.model.teammembership import TeamParticipation
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.identity.interfaces.account import AccountStatus
 from lp.services.identity.model.account import Account
 from lp.soyuz.enums import ArchiveSubscriberStatus
@@ -36,7 +28,7 @@ from lp.soyuz.interfaces.archiveauthtoken import (
 
 
 @implementer(IArchiveAuthToken)
-class ArchiveAuthToken(Storm):
+class ArchiveAuthToken(StormBase):
     """See `IArchiveAuthToken`."""
 
     __storm_table__ = "ArchiveAuthToken"
diff --git a/lib/lp/soyuz/model/archivefile.py b/lib/lp/soyuz/model/archivefile.py
index 43e27b9..b7170dc 100644
--- a/lib/lp/soyuz/model/archivefile.py
+++ b/lib/lp/soyuz/model/archivefile.py
@@ -12,7 +12,7 @@ import os.path
 import re
 
 import pytz
-from storm.locals import And, DateTime, Int, Reference, Storm, Unicode
+from storm.locals import And, DateTime, Int, Reference, Unicode
 from zope.component import getUtility
 from zope.interface import implementer
 
@@ -21,6 +21,7 @@ from lp.services.database.constants import UTC_NOW
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.interfaces import IPrimaryStore, IStore
 from lp.services.database.sqlbase import convert_storm_clause_to_string
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import RegexpMatch
 from lp.services.librarian.interfaces import ILibraryFileAliasSet
 from lp.services.librarian.model import LibraryFileAlias, LibraryFileContent
@@ -37,7 +38,7 @@ def _now():
 
 
 @implementer(IArchiveFile)
-class ArchiveFile(Storm):
+class ArchiveFile(StormBase):
     """See `IArchiveFile`."""
 
     __storm_table__ = "ArchiveFile"
diff --git a/lib/lp/soyuz/model/archivesubscriber.py b/lib/lp/soyuz/model/archivesubscriber.py
index b733c52..95ee026 100644
--- a/lib/lp/soyuz/model/archivesubscriber.py
+++ b/lib/lp/soyuz/model/archivesubscriber.py
@@ -11,7 +11,7 @@ from operator import itemgetter
 
 import pytz
 from storm.expr import And, Desc, Join, LeftJoin
-from storm.locals import DateTime, Int, Reference, Store, Storm, Unicode
+from storm.locals import DateTime, Int, Reference, Store, Unicode
 from storm.store import EmptyResultSet
 from zope.component import getUtility
 from zope.interface import implementer
@@ -24,6 +24,7 @@ from lp.services.database.bulk import load_related
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
+from lp.services.database.stormbase import StormBase
 from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
 from lp.services.identity.model.emailaddress import EmailAddress
 from lp.services.webapp.authorization import precache_permission_for_objects
@@ -38,7 +39,7 @@ from lp.soyuz.model.archiveauthtoken import ArchiveAuthToken
 
 
 @implementer(IArchiveSubscriber)
-class ArchiveSubscriber(Storm):
+class ArchiveSubscriber(StormBase):
     """See `IArchiveSubscriber`."""
 
     __storm_table__ = "ArchiveSubscriber"
diff --git a/lib/lp/soyuz/model/binarypackagerelease.py b/lib/lp/soyuz/model/binarypackagerelease.py
index 41ac6b5..0d97f44 100644
--- a/lib/lp/soyuz/model/binarypackagerelease.py
+++ b/lib/lp/soyuz/model/binarypackagerelease.py
@@ -11,7 +11,7 @@ import re
 from operator import attrgetter
 from typing import Any
 
-from storm.locals import Date, Int, Reference, Store, Storm
+from storm.locals import Date, Int, Reference, Store
 from zope.component import getUtility
 from zope.interface import implementer
 
@@ -27,6 +27,7 @@ from lp.services.database.sqlobject import (
     IntCol,
     StringCol,
 )
+from lp.services.database.stormbase import StormBase
 from lp.services.propertycache import cachedproperty, get_property_cache
 from lp.soyuz.enums import (
     BinaryPackageFileType,
@@ -265,7 +266,7 @@ class BinaryPackageRelease(SQLBase):
 
 
 @implementer(IBinaryPackageReleaseDownloadCount)
-class BinaryPackageReleaseDownloadCount(Storm):
+class BinaryPackageReleaseDownloadCount(StormBase):
     """See `IBinaryPackageReleaseDownloadCount`."""
 
     __storm_table__ = "BinaryPackageReleaseDownloadCount"
diff --git a/lib/lp/soyuz/model/distroarchseriesfilter.py b/lib/lp/soyuz/model/distroarchseriesfilter.py
index ac48343..c866917 100644
--- a/lib/lp/soyuz/model/distroarchseriesfilter.py
+++ b/lib/lp/soyuz/model/distroarchseriesfilter.py
@@ -8,13 +8,14 @@ __all__ = [
 ]
 
 import pytz
-from storm.locals import DateTime, Int, Reference, Storm
+from storm.locals import DateTime, Int, Reference
 from zope.interface import implementer
 from zope.security.proxy import removeSecurityProxy
 
 from lp.services.database.constants import DEFAULT, UTC_NOW
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.soyuz.enums import DistroArchSeriesFilterSense
 from lp.soyuz.interfaces.distroarchseriesfilter import (
     IDistroArchSeriesFilter,
@@ -32,7 +33,7 @@ def distro_arch_series_filter_modified(pss, event):
 
 
 @implementer(IDistroArchSeriesFilter)
-class DistroArchSeriesFilter(Storm):
+class DistroArchSeriesFilter(StormBase):
     """See `IDistroArchSeriesFilter`."""
 
     __storm_table__ = "DistroArchSeriesFilter"
diff --git a/lib/lp/soyuz/model/livefs.py b/lib/lp/soyuz/model/livefs.py
index 1f19e00..f7b650b 100644
--- a/lib/lp/soyuz/model/livefs.py
+++ b/lib/lp/soyuz/model/livefs.py
@@ -22,7 +22,6 @@ from storm.locals import (
     Not,
     Reference,
     Store,
-    Storm,
     TimeDelta,
     Unicode,
 )
@@ -43,6 +42,7 @@ from lp.registry.interfaces.role import IHasOwner
 from lp.registry.model.person import Person, get_person_visibility_terms
 from lp.services.database.constants import DEFAULT, UTC_NOW
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import Greatest, IsDistinctFrom, NullsLast
 from lp.services.features import getFeatureFlag
 from lp.services.webapp.interfaces import ILaunchBag
@@ -76,7 +76,7 @@ def livefs_modified(livefs, event):
 
 
 @implementer(ILiveFS, IHasOwner)
-class LiveFS(Storm, WebhookTargetMixin):
+class LiveFS(StormBase, WebhookTargetMixin):
     """See `ILiveFS`."""
 
     __storm_table__ = "LiveFS"
diff --git a/lib/lp/soyuz/model/livefsbuild.py b/lib/lp/soyuz/model/livefsbuild.py
index 32d9193..23112f0 100644
--- a/lib/lp/soyuz/model/livefsbuild.py
+++ b/lib/lp/soyuz/model/livefsbuild.py
@@ -20,7 +20,6 @@ from storm.locals import (
     Reference,
     Select,
     Store,
-    Storm,
     Unicode,
 )
 from storm.store import EmptyResultSet
@@ -42,6 +41,7 @@ from lp.services.database.constants import DEFAULT
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.services.features import getFeatureFlag
 from lp.services.librarian.browser import ProxiedLibraryFileAlias
 from lp.services.librarian.model import LibraryFileAlias, LibraryFileContent
@@ -69,7 +69,7 @@ from lp.soyuz.model.archivedependency import ArchiveDependency
 
 
 @implementer(ILiveFSFile)
-class LiveFSFile(Storm):
+class LiveFSFile(StormBase):
     """See `ILiveFS`."""
 
     __storm_table__ = "LiveFSFile"
@@ -90,7 +90,7 @@ class LiveFSFile(Storm):
 
 
 @implementer(ILiveFSBuild)
-class LiveFSBuild(PackageBuildMixin, Storm):
+class LiveFSBuild(PackageBuildMixin, StormBase):
     """See `ILiveFSBuild`."""
 
     __storm_table__ = "LiveFSBuild"
diff --git a/lib/lp/soyuz/model/packagecopyrequest.py b/lib/lp/soyuz/model/packagecopyrequest.py
index da1706b..bc8b815 100644
--- a/lib/lp/soyuz/model/packagecopyrequest.py
+++ b/lib/lp/soyuz/model/packagecopyrequest.py
@@ -5,13 +5,14 @@ __all__ = ["PackageCopyRequest", "PackageCopyRequestSet"]
 
 import itertools
 
-from storm.locals import Bool, DateTime, Enum, Int, Reference, Storm, Unicode
+from storm.locals import Bool, DateTime, Enum, Int, Reference, Unicode
 from zope.interface import implementer
 
 from lp.registry.interfaces.person import validate_public_person
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.soyuz.enums import PackageCopyStatus
 from lp.soyuz.interfaces.packagecopyrequest import (
     IPackageCopyRequest,
@@ -25,7 +26,7 @@ def _construct_enum_mapping(db_item_cls):
 
 
 @implementer(IPackageCopyRequest)
-class PackageCopyRequest(Storm):
+class PackageCopyRequest(StormBase):
     """See `IPackageCopyRequest`."""
 
     __storm_table__ = "PackageCopyRequest"
diff --git a/lib/lp/soyuz/model/packageset.py b/lib/lp/soyuz/model/packageset.py
index 7b4ee88..6091f74 100644
--- a/lib/lp/soyuz/model/packageset.py
+++ b/lib/lp/soyuz/model/packageset.py
@@ -6,7 +6,7 @@ __all__ = ["Packageset", "PackagesetSet"]
 import pytz
 import six
 from storm.expr import SQL
-from storm.locals import DateTime, Int, Reference, Storm, Unicode
+from storm.locals import DateTime, Int, Reference, Unicode
 from zope.component import getUtility
 from zope.interface import implementer
 
@@ -16,6 +16,7 @@ from lp.registry.interfaces.sourcepackagename import (
 )
 from lp.registry.model.sourcepackagename import SourcePackageName
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.soyuz.interfaces.packageset import (
     DuplicatePackagesetName,
     IPackageset,
@@ -32,7 +33,7 @@ def _order_result_set(result_set):
 
 
 @implementer(IPackageset)
-class Packageset(Storm):
+class Packageset(StormBase):
     """See `IPackageset`."""
 
     __storm_table__ = "Packageset"
diff --git a/lib/lp/soyuz/model/packagesetgroup.py b/lib/lp/soyuz/model/packagesetgroup.py
index 04a4f10..aac5867 100644
--- a/lib/lp/soyuz/model/packagesetgroup.py
+++ b/lib/lp/soyuz/model/packagesetgroup.py
@@ -6,14 +6,15 @@ __all__ = [
 ]
 
 import pytz
-from storm.locals import DateTime, Int, Reference, Storm
+from storm.locals import DateTime, Int, Reference
 from zope.interface import implementer
 
+from lp.services.database.stormbase import StormBase
 from lp.soyuz.interfaces.packagesetgroup import IPackagesetGroup
 
 
 @implementer(IPackagesetGroup)
-class PackagesetGroup(Storm):
+class PackagesetGroup(StormBase):
     """See `IPackageset`."""
 
     __storm_table__ = "PackagesetGroup"
diff --git a/lib/lp/soyuz/model/packagesetsources.py b/lib/lp/soyuz/model/packagesetsources.py
index 94a7bd2..11ba685 100644
--- a/lib/lp/soyuz/model/packagesetsources.py
+++ b/lib/lp/soyuz/model/packagesetsources.py
@@ -10,10 +10,12 @@ __all__ = [
     "PackagesetSources",
 ]
 
-from storm.locals import Int, Reference, Storm
+from storm.locals import Int, Reference
 
+from lp.services.database.stormbase import StormBase
 
-class PackagesetSources(Storm):
+
+class PackagesetSources(StormBase):
     """Linking table: which packages are in a package set?"""
 
     # This table is largely managed from Packageset, but also directly
diff --git a/lib/lp/soyuz/model/reporting.py b/lib/lp/soyuz/model/reporting.py
index 126217c..1054da8 100644
--- a/lib/lp/soyuz/model/reporting.py
+++ b/lib/lp/soyuz/model/reporting.py
@@ -6,12 +6,12 @@ __all__ = [
 ]
 
 from lazr.delegates import delegate_to
-from storm.base import Storm
 from storm.locals import Int, Reference
 from storm.properties import DateTime
 from zope.interface import implementer
 
 from lp.services.database.enumcol import DBEnum
+from lp.services.database.stormbase import StormBase
 from lp.soyuz.enums import ArchivePurpose
 from lp.soyuz.interfaces.reporting import (
     ILatestPersonSourcePackageReleaseCache,
@@ -21,7 +21,7 @@ from lp.soyuz.interfaces.sourcepackagerelease import ISourcePackageRelease
 
 @implementer(ILatestPersonSourcePackageReleaseCache)
 @delegate_to(ISourcePackageRelease, context="sourcepackagerelease")
-class LatestPersonSourcePackageReleaseCache(Storm):
+class LatestPersonSourcePackageReleaseCache(StormBase):
     """See `LatestPersonSourcePackageReleaseCache`."""
 
     __storm_table__ = "LatestPersonSourcePackageReleaseCache"
diff --git a/lib/lp/soyuz/model/sourcepackageformat.py b/lib/lp/soyuz/model/sourcepackageformat.py
index 49dd49a..cae5565 100644
--- a/lib/lp/soyuz/model/sourcepackageformat.py
+++ b/lib/lp/soyuz/model/sourcepackageformat.py
@@ -6,11 +6,12 @@ __all__ = [
     "SourcePackageFormatSelectionSet",
 ]
 
-from storm.locals import Int, Reference, Storm
+from storm.locals import Int, Reference
 from zope.interface import implementer
 
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IPrimaryStore, IStore
+from lp.services.database.stormbase import StormBase
 from lp.soyuz.enums import SourcePackageFormat
 from lp.soyuz.interfaces.sourcepackageformat import (
     ISourcePackageFormatSelection,
@@ -19,7 +20,7 @@ from lp.soyuz.interfaces.sourcepackageformat import (
 
 
 @implementer(ISourcePackageFormatSelection)
-class SourcePackageFormatSelection(Storm):
+class SourcePackageFormatSelection(StormBase):
     """See ISourcePackageFormatSelection."""
 
     __storm_table__ = "sourcepackageformatselection"
diff --git a/lib/lp/translations/model/translationtemplatesbuild.py b/lib/lp/translations/model/translationtemplatesbuild.py
index 950583f..32c6a6f 100644
--- a/lib/lp/translations/model/translationtemplatesbuild.py
+++ b/lib/lp/translations/model/translationtemplatesbuild.py
@@ -12,7 +12,7 @@ import logging
 from datetime import timedelta
 
 import pytz
-from storm.locals import Bool, DateTime, Int, Reference, Storm
+from storm.locals import Bool, DateTime, Int, Reference
 from zope.component import getUtility
 from zope.interface import implementer, provider
 from zope.security.proxy import removeSecurityProxy
@@ -32,6 +32,7 @@ from lp.services.database.bulk import load_related
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IStore
+from lp.services.database.stormbase import StormBase
 from lp.translations.interfaces.translationtemplatesbuild import (
     ITranslationTemplatesBuild,
     ITranslationTemplatesBuildSource,
@@ -44,7 +45,7 @@ HARDCODED_TRANSLATIONTEMPLATESBUILD_SCORE = 2515
 @implementer(ITranslationTemplatesBuild)
 @provider(ITranslationTemplatesBuildSource)
 class TranslationTemplatesBuild(
-    SpecificBuildFarmJobSourceMixin, BuildFarmJobMixin, Storm
+    SpecificBuildFarmJobSourceMixin, BuildFarmJobMixin, StormBase
 ):
     """A `BuildFarmJob` extension for translation templates builds."""
 
diff --git a/setup.cfg b/setup.cfg
index f93f218..0172a8a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -211,6 +211,11 @@ ignore =
     # operators, at least for now.
     W503,
     W504
+enable-extensions = B1
+warn-symbols =
+    # It's OK to override these warnings in the case of isinstance checks.
+    storm.base.Storm = Inherit from lp.services.database.stormbase.StormBase instead.
+    storm.locals.Storm = Inherit from lp.services.database.stormbase.StormBase instead.
 
 [isort]
 # database/* have some implicit relative imports.