Patchwork extensions: extract partial application into a bind() function

login
register
mail settings
Submitter Eric Sumner
Date April 15, 2015, 4:24 p.m.
Message ID <a8fd41a5a5c1568efa8c.1429115080@waste.org>
Download mbox | patch
Permalink /patch/8678/
State Superseded
Commit fb6cb1b82f4fb6409b21447b2902d266e1a63266
Headers show

Comments

Eric Sumner - April 15, 2015, 4:24 p.m.
# HG changeset patch
# User Eric Sumner <ericsumner@fb.com>
# Date 1429114685 14400
#      Wed Apr 15 12:18:05 2015 -0400
# Node ID a8fd41a5a5c1568efa8c1de185a888d6c558f067
# Parent  c560d8c687916cb70a6d54c2c9ddcb5c9e457be2
extensions: extract partial application into a bind() function

We use partial function application for wrapping existing Mercurial functions,
and it's implemented separately each time.  This patch extracts the partial
application into a new bind() function that can be used on its own by extensions
when appropriate.

In particular, the evolve extension needs to wrap functions in the various
bundle2 processing dictionaries, which the pre-existing methods don't support.
Matt Mackall - April 15, 2015, 4:32 p.m.
On Wed, 2015-04-15 at 11:24 -0500, Eric Sumner wrote:
> # HG changeset patch
> # User Eric Sumner <ericsumner@fb.com>
> # Date 1429114685 14400
> #      Wed Apr 15 12:18:05 2015 -0400
> # Node ID a8fd41a5a5c1568efa8c1de185a888d6c558f067
> # Parent  c560d8c687916cb70a6d54c2c9ddcb5c9e457be2
> extensions: extract partial application into a bind() function

FYI, I'm making Eric send this multiple times to help me test the
pushgate.

Patch

diff --git a/mercurial/extensions.py b/mercurial/extensions.py
--- a/mercurial/extensions.py
+++ b/mercurial/extensions.py
@@ -152,6 +152,18 @@ 
     else:
         _aftercallbacks.setdefault(extension, []).append(callback)
 
+def bind(func, *args):
+    '''Partial function application
+
+      Returns a new function that is the partial application of args and kwargs
+      to func.  For example,
+      
+          f(1, 2, bar=3) === bind(f, 1)(2, bar=3)'''
+    assert callable(func)
+    def closure(*a, **kw):
+        return func(*(args + a), **kw)
+    return closure
+
 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
     '''Wrap the command named `command' in table
 
@@ -189,9 +201,7 @@ 
             break
 
     origfn = entry[0]
-    def wrap(*args, **kwargs):
-        return util.checksignature(wrapper)(
-            util.checksignature(origfn), *args, **kwargs)
+    wrap = bind(util.checksignature(wrapper), util.checksignature(origfn))
 
     wrap.__module__ = getattr(origfn, '__module__')
 
@@ -241,12 +251,10 @@ 
     subclass trick.
     '''
     assert callable(wrapper)
-    def wrap(*args, **kwargs):
-        return wrapper(origfn, *args, **kwargs)
 
     origfn = getattr(container, funcname)
     assert callable(origfn)
-    setattr(container, funcname, wrap)
+    setattr(container, funcname, bind(wrapper, origfn))
     return origfn
 
 def _disabledpaths(strip_init=False):