Patchwork D3419: interfaceutil: module to stub out zope.interface

login
register
mail settings
Submitter phabricator
Date April 23, 2018, 8:29 p.m.
Message ID <800750916f90ee72ecdf7e2e26766731@localhost.localdomain>
Download mbox | patch
Permalink /patch/31215/
State Not Applicable
Headers show

Comments

phabricator - April 23, 2018, 8:29 p.m.
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG856f381ad74b: interfaceutil: module to stub out zope.interface (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3419?vs=8417&id=8423

REVISION DETAIL
  https://phab.mercurial-scm.org/D3419

AFFECTED FILES
  mercurial/filelog.py
  mercurial/httppeer.py
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/utils/interfaceutil.py
  mercurial/wireprotoserver.py
  mercurial/wireprototypes.py
  mercurial/wireprotov1peer.py
  mercurial/wireprotov2server.py
  tests/test-check-interfaces.py
  tests/test-check-module-imports.t

CHANGE DETAILS




To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel

Patch

diff --git a/tests/test-check-module-imports.t b/tests/test-check-module-imports.t
--- a/tests/test-check-module-imports.t
+++ b/tests/test-check-module-imports.t
@@ -27,6 +27,7 @@ 
   > -X i18n/posplit \
   > -X mercurial/thirdparty \
   > -X tests/hypothesishelpers.py \
+  > -X tests/test-check-interfaces.py \
   > -X tests/test-commit-interactive.t \
   > -X tests/test-contrib-check-code.t \
   > -X tests/test-demandimport.py \
diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py
--- a/tests/test-check-interfaces.py
+++ b/tests/test-check-interfaces.py
@@ -2,6 +2,9 @@ 
 
 from __future__ import absolute_import, print_function
 
+from mercurial import encoding
+encoding.environ[b'HGREALINTERFACES'] = b'1'
+
 import os
 
 from mercurial.thirdparty.zope import (
diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py
--- a/mercurial/wireprotov2server.py
+++ b/mercurial/wireprotov2server.py
@@ -12,9 +12,6 @@ 
 from .thirdparty import (
     cbor,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     encoding,
     error,
@@ -24,6 +21,9 @@ 
     wireprotoframing,
     wireprototypes,
 )
+from .utils import (
+    interfaceutil,
+)
 
 FRAMINGTYPE = b'application/mercurial-exp-framing-0005'
 
@@ -340,7 +340,7 @@ 
 
     return func(repo, proto, **args)
 
-@zi.implementer(wireprototypes.baseprotocolhandler)
+@interfaceutil.implementer(wireprototypes.baseprotocolhandler)
 class httpv2protocolhandler(object):
     def __init__(self, req, ui, args=None):
         self._req = req
diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py
--- a/mercurial/wireprotov1peer.py
+++ b/mercurial/wireprotov1peer.py
@@ -15,9 +15,6 @@ 
 from .node import (
     bin,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     bundle2,
     changegroup as changegroupmod,
@@ -29,6 +26,9 @@ 
     util,
     wireprototypes,
 )
+from .utils import (
+    interfaceutil,
+)
 
 urlreq = util.urlreq
 
@@ -110,7 +110,7 @@ 
         # on that.
         return self.result(timeout)
 
-@zi.implementer(repository.ipeercommandexecutor)
+@interfaceutil.implementer(repository.ipeercommandexecutor)
 class peerexecutor(object):
     def __init__(self, peer):
         self._peer = peer
@@ -308,7 +308,8 @@ 
             else:
                 f.set_result(result)
 
-@zi.implementer(repository.ipeercommands, repository.ipeerlegacycommands)
+@interfaceutil.implementer(repository.ipeercommands,
+                           repository.ipeerlegacycommands)
 class wirepeer(repository.peer):
     """Client-side interface for communicating with a peer repository.
 
diff --git a/mercurial/wireprototypes.py b/mercurial/wireprototypes.py
--- a/mercurial/wireprototypes.py
+++ b/mercurial/wireprototypes.py
@@ -9,14 +9,14 @@ 
     bin,
     hex,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from .i18n import _
 from . import (
     error,
     util,
 )
+from .utils import (
+    interfaceutil,
+)
 
 # Names of the SSH protocol implementations.
 SSHV1 = 'ssh-v1'
@@ -179,16 +179,16 @@ 
     'stream': 'boolean',
 }
 
-class baseprotocolhandler(zi.Interface):
+class baseprotocolhandler(interfaceutil.Interface):
     """Abstract base class for wire protocol handlers.
 
     A wire protocol handler serves as an interface between protocol command
     handlers and the wire protocol transport layer. Protocol handlers provide
     methods to read command arguments, redirect stdio for the duration of
     the request, handle response types, etc.
     """
 
-    name = zi.Attribute(
+    name = interfaceutil.Attribute(
         """The name of the protocol implementation.
 
         Used for uniquely identifying the transport type.
diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -15,9 +15,6 @@ 
 from .thirdparty import (
     cbor,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     encoding,
     error,
@@ -29,6 +26,7 @@ 
     wireprotov2server,
 )
 from .utils import (
+    interfaceutil,
     procutil,
 )
 
@@ -62,7 +60,7 @@ 
 
     return ''.join(chunks)
 
-@zi.implementer(wireprototypes.baseprotocolhandler)
+@interfaceutil.implementer(wireprototypes.baseprotocolhandler)
 class httpv1protocolhandler(object):
     def __init__(self, req, ui, checkperm):
         self._req = req
@@ -489,7 +487,7 @@ 
     fout.write(b'\n')
     fout.flush()
 
-@zi.implementer(wireprototypes.baseprotocolhandler)
+@interfaceutil.implementer(wireprototypes.baseprotocolhandler)
 class sshv1protocolhandler(object):
     """Handler for requests services via version 1 of SSH protocol."""
     def __init__(self, ui, fin, fout):
diff --git a/mercurial/utils/interfaceutil.py b/mercurial/utils/interfaceutil.py
new file mode 100644
--- /dev/null
+++ b/mercurial/utils/interfaceutil.py
@@ -0,0 +1,40 @@ 
+# interfaceutil.py - Utilities for declaring interfaces.
+#
+# Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+# zope.interface imposes a run-time cost due to module import overhead and
+# bookkeeping for declaring interfaces. So, we use stubs for various
+# zope.interface primitives unless instructed otherwise.
+
+from __future__ import absolute_import
+
+from .. import (
+    encoding,
+)
+
+if encoding.environ.get('HGREALINTERFACES'):
+    from ..thirdparty.zope import (
+        interface as zi,
+    )
+
+    Attribute = zi.Attribute
+    Interface = zi.Interface
+    implementer = zi.implementer
+else:
+    class Attribute(object):
+        def __init__(self, __name__, __doc__=''):
+            pass
+
+    class Interface(object):
+        def __init__(self, name, bases=(), attrs=None, __doc__=None,
+                 __module__=None):
+            pass
+
+    def implementer(*ifaces):
+        def wrapper(cls):
+            return cls
+
+        return wrapper
diff --git a/mercurial/repository.py b/mercurial/repository.py
--- a/mercurial/repository.py
+++ b/mercurial/repository.py
@@ -8,23 +8,23 @@ 
 from __future__ import absolute_import
 
 from .i18n import _
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     error,
 )
+from .utils import (
+    interfaceutil,
+)
 
-class ipeerconnection(zi.Interface):
+class ipeerconnection(interfaceutil.Interface):
     """Represents a "connection" to a repository.
 
     This is the base interface for representing a connection to a repository.
     It holds basic properties and methods applicable to all peer types.
 
     This is not a complete interface definition and should not be used
     outside of this module.
     """
-    ui = zi.Attribute("""ui.ui instance""")
+    ui = interfaceutil.Attribute("""ui.ui instance""")
 
     def url():
         """Returns a URL string representing this peer.
@@ -61,7 +61,7 @@ 
         associated with the peer should be cleaned up.
         """
 
-class ipeercapabilities(zi.Interface):
+class ipeercapabilities(interfaceutil.Interface):
     """Peer sub-interface related to capabilities."""
 
     def capable(name):
@@ -81,7 +81,7 @@ 
         Raises a ``CapabilityError`` if the capability isn't present.
         """
 
-class ipeercommands(zi.Interface):
+class ipeercommands(interfaceutil.Interface):
     """Client-side interface for communicating over the wire protocol.
 
     This interface is used as a gateway to the Mercurial wire protocol.
@@ -170,7 +170,7 @@ 
         Returns the integer number of heads added to the peer.
         """
 
-class ipeerlegacycommands(zi.Interface):
+class ipeerlegacycommands(interfaceutil.Interface):
     """Interface for implementing support for legacy wire protocol commands.
 
     Wire protocol commands transition to legacy status when they are no longer
@@ -202,7 +202,7 @@ 
     def changegroupsubset(bases, heads, source):
         pass
 
-class ipeercommandexecutor(zi.Interface):
+class ipeercommandexecutor(interfaceutil.Interface):
     """Represents a mechanism to execute remote commands.
 
     This is the primary interface for requesting that wire protocol commands
@@ -259,7 +259,7 @@ 
         This method may call ``sendcommands()`` if there are buffered commands.
         """
 
-class ipeerrequests(zi.Interface):
+class ipeerrequests(interfaceutil.Interface):
     """Interface for executing commands on a peer."""
 
     def commandexecutor():
@@ -290,7 +290,7 @@ 
     All peer instances must conform to this interface.
     """
 
-@zi.implementer(ipeerbase)
+@interfaceutil.implementer(ipeerbase)
 class peer(object):
     """Base class for peer repositories."""
 
@@ -314,7 +314,7 @@ 
             _('cannot %s; remote repository does not support the %r '
               'capability') % (purpose, name))
 
-class ifilerevisionssequence(zi.Interface):
+class ifilerevisionssequence(interfaceutil.Interface):
     """Contains index data for all revisions of a file.
 
     Types implementing this behave like lists of tuples. The index
@@ -365,7 +365,7 @@ 
     def insert(self, i, entry):
         """Add an item to the index at specific revision."""
 
-class ifileindex(zi.Interface):
+class ifileindex(interfaceutil.Interface):
     """Storage interface for index data of a single file.
 
     File storage data is divided into index metadata and data storage.
@@ -377,7 +377,7 @@ 
     * DAG data (storing and querying the relationship between nodes).
     * Metadata to facilitate storage.
     """
-    index = zi.Attribute(
+    index = interfaceutil.Attribute(
         """An ``ifilerevisionssequence`` instance.""")
 
     def __len__():
@@ -470,7 +470,7 @@ 
     def candelta(baserev, rev):
         """"Whether a delta can be generated between two revisions."""
 
-class ifiledata(zi.Interface):
+class ifiledata(interfaceutil.Interface):
     """Storage interface for data storage of a specific file.
 
     This complements ``ifileindex`` and provides an interface for accessing
@@ -536,7 +536,7 @@ 
         revision data.
         """
 
-class ifilemutation(zi.Interface):
+class ifilemutation(interfaceutil.Interface):
     """Storage interface for mutation events of a tracked file."""
 
     def add(filedata, meta, transaction, linkrev, p1, p2):
@@ -608,21 +608,21 @@ 
 class ifilestorage(ifileindex, ifiledata, ifilemutation):
     """Complete storage interface for a single tracked file."""
 
-    version = zi.Attribute(
+    version = interfaceutil.Attribute(
         """Version number of storage.
 
         TODO this feels revlog centric and could likely be removed.
         """)
 
-    storedeltachains = zi.Attribute(
+    storedeltachains = interfaceutil.Attribute(
         """Whether the store stores deltas.
 
         TODO deltachains are revlog centric. This can probably removed
         once there are better abstractions for obtaining/writing
         data.
         """)
 
-    _generaldelta = zi.Attribute(
+    _generaldelta = interfaceutil.Attribute(
         """Whether deltas can be against any parent revision.
 
         TODO this is used by changegroup code and it could probably be
@@ -642,100 +642,100 @@ 
         TODO this is used by verify and it should not be part of the interface.
         """
 
-class completelocalrepository(zi.Interface):
+class completelocalrepository(interfaceutil.Interface):
     """Monolithic interface for local repositories.
 
     This currently captures the reality of things - not how things should be.
     """
 
-    supportedformats = zi.Attribute(
+    supportedformats = interfaceutil.Attribute(
         """Set of requirements that apply to stream clone.
 
         This is actually a class attribute and is shared among all instances.
         """)
 
-    openerreqs = zi.Attribute(
+    openerreqs = interfaceutil.Attribute(
         """Set of requirements that are passed to the opener.
 
         This is actually a class attribute and is shared among all instances.
         """)
 
-    supported = zi.Attribute(
+    supported = interfaceutil.Attribute(
         """Set of requirements that this repo is capable of opening.""")
 
-    requirements = zi.Attribute(
+    requirements = interfaceutil.Attribute(
         """Set of requirements this repo uses.""")
 
-    filtername = zi.Attribute(
+    filtername = interfaceutil.Attribute(
         """Name of the repoview that is active on this repo.""")
 
-    wvfs = zi.Attribute(
+    wvfs = interfaceutil.Attribute(
         """VFS used to access the working directory.""")
 
-    vfs = zi.Attribute(
+    vfs = interfaceutil.Attribute(
         """VFS rooted at the .hg directory.
 
         Used to access repository data not in the store.
         """)
 
-    svfs = zi.Attribute(
+    svfs = interfaceutil.Attribute(
         """VFS rooted at the store.
 
         Used to access repository data in the store. Typically .hg/store.
         But can point elsewhere if the store is shared.
         """)
 
-    root = zi.Attribute(
+    root = interfaceutil.Attribute(
         """Path to the root of the working directory.""")
 
-    path = zi.Attribute(
+    path = interfaceutil.Attribute(
         """Path to the .hg directory.""")
 
-    origroot = zi.Attribute(
+    origroot = interfaceutil.Attribute(
         """The filesystem path that was used to construct the repo.""")
 
-    auditor = zi.Attribute(
+    auditor = interfaceutil.Attribute(
         """A pathauditor for the working directory.
 
         This checks if a path refers to a nested repository.
 
         Operates on the filesystem.
         """)
 
-    nofsauditor = zi.Attribute(
+    nofsauditor = interfaceutil.Attribute(
         """A pathauditor for the working directory.
 
         This is like ``auditor`` except it doesn't do filesystem checks.
         """)
 
-    baseui = zi.Attribute(
+    baseui = interfaceutil.Attribute(
         """Original ui instance passed into constructor.""")
 
-    ui = zi.Attribute(
+    ui = interfaceutil.Attribute(
         """Main ui instance for this instance.""")
 
-    sharedpath = zi.Attribute(
+    sharedpath = interfaceutil.Attribute(
         """Path to the .hg directory of the repo this repo was shared from.""")
 
-    store = zi.Attribute(
+    store = interfaceutil.Attribute(
         """A store instance.""")
 
-    spath = zi.Attribute(
+    spath = interfaceutil.Attribute(
         """Path to the store.""")
 
-    sjoin = zi.Attribute(
+    sjoin = interfaceutil.Attribute(
         """Alias to self.store.join.""")
 
-    cachevfs = zi.Attribute(
+    cachevfs = interfaceutil.Attribute(
         """A VFS used to access the cache directory.
 
         Typically .hg/cache.
         """)
 
-    filteredrevcache = zi.Attribute(
+    filteredrevcache = interfaceutil.Attribute(
         """Holds sets of revisions to be filtered.""")
 
-    names = zi.Attribute(
+    names = interfaceutil.Attribute(
         """A ``namespaces`` instance.""")
 
     def close():
@@ -750,19 +750,19 @@ 
     def filtered(name, visibilityexceptions=None):
         """Obtain a named view of this repository."""
 
-    obsstore = zi.Attribute(
+    obsstore = interfaceutil.Attribute(
         """A store of obsolescence data.""")
 
-    changelog = zi.Attribute(
+    changelog = interfaceutil.Attribute(
         """A handle on the changelog revlog.""")
 
-    manifestlog = zi.Attribute(
+    manifestlog = interfaceutil.Attribute(
         """A handle on the root manifest revlog.""")
 
-    dirstate = zi.Attribute(
+    dirstate = interfaceutil.Attribute(
         """Working directory state.""")
 
-    narrowpats = zi.Attribute(
+    narrowpats = interfaceutil.Attribute(
         """Matcher patterns for this repository's narrowspec.""")
 
     def narrowmatch():
@@ -978,7 +978,7 @@ 
     def checkpush(pushop):
         pass
 
-    prepushoutgoinghooks = zi.Attribute(
+    prepushoutgoinghooks = interfaceutil.Attribute(
         """util.hooks instance.""")
 
     def pushkey(namespace, key, old, new):
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -21,9 +21,6 @@ 
     nullid,
     short,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     bookmarks,
     branchmap,
@@ -68,6 +65,7 @@ 
     vfs as vfsmod,
 )
 from .utils import (
+    interfaceutil,
     procutil,
     stringutil,
 )
@@ -153,7 +151,7 @@ 
               'unbundle'}
 legacycaps = moderncaps.union({'changegroupsubset'})
 
-@zi.implementer(repository.ipeercommandexecutor)
+@interfaceutil.implementer(repository.ipeercommandexecutor)
 class localcommandexecutor(object):
     def __init__(self, peer):
         self._peer = peer
@@ -196,7 +194,7 @@ 
     def close(self):
         self._closed = True
 
-@zi.implementer(repository.ipeercommands)
+@interfaceutil.implementer(repository.ipeercommands)
 class localpeer(repository.peer):
     '''peer for a local repo; reflects only the most recent API'''
 
@@ -324,7 +322,7 @@ 
 
     # End of peer interface.
 
-@zi.implementer(repository.ipeerlegacycommands)
+@interfaceutil.implementer(repository.ipeerlegacycommands)
 class locallegacypeer(localpeer):
     '''peer extension which implements legacy methods too; used for tests with
     restricted capabilities'''
@@ -365,7 +363,7 @@ 
 # set to reflect that the extension knows how to handle that requirements.
 featuresetupfuncs = set()
 
-@zi.implementer(repository.completelocalrepository)
+@interfaceutil.implementer(repository.completelocalrepository)
 class localrepository(object):
 
     # obsolete experimental requirements:
diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -20,9 +20,6 @@ 
 from .thirdparty import (
     cbor,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     bundle2,
     error,
@@ -38,6 +35,9 @@ 
     wireprotov2peer,
     wireprotov2server,
 )
+from .utils import (
+    interfaceutil,
+)
 
 httplib = util.httplib
 urlerr = util.urlerr
@@ -582,7 +582,7 @@ 
         # will resolve to Future.result.
         return self.result(timeout)
 
-@zi.implementer(repository.ipeercommandexecutor)
+@interfaceutil.implementer(repository.ipeercommandexecutor)
 class httpv2executor(object):
     def __init__(self, ui, opener, requestbuilder, apiurl, descriptor):
         self._ui = ui
@@ -731,8 +731,9 @@ 
             pass
 
 # TODO implement interface for version 2 peers
-@zi.implementer(repository.ipeerconnection, repository.ipeercapabilities,
-                repository.ipeerrequests)
+@interfaceutil.implementer(repository.ipeerconnection,
+                           repository.ipeercapabilities,
+                           repository.ipeerrequests)
 class httpv2peer(object):
     def __init__(self, ui, repourl, apipath, opener, requestbuilder,
                  apidescriptor):
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -7,16 +7,16 @@ 
 
 from __future__ import absolute_import
 
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     error,
     repository,
     revlog,
 )
+from .utils import (
+    interfaceutil,
+)
 
-@zi.implementer(repository.ifilestorage)
+@interfaceutil.implementer(repository.ifilestorage)
 class filelog(object):
     def __init__(self, opener, path):
         self._revlog = revlog.revlog(opener,