Patchwork [V2] revset: add extra data to filteredset for better inspection

login
register
mail settings
Submitter Yuya Nishihara
Date Feb. 28, 2016, 6:38 a.m.
Message ID <f8df065a49aecbc9b788.1456641491@mimosa>
Download mbox | patch
Permalink /patch/13447/
State Accepted
Headers show

Comments

Yuya Nishihara - Feb. 28, 2016, 6:38 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1455359111 -32400
#      Sat Feb 13 19:25:11 2016 +0900
# Node ID f8df065a49aecbc9b78869c38890ba2cce6afaa6
# Parent  10eaae94523c790d7b77c52a4cb4bfcf406021ef
revset: add extra data to filteredset for better inspection

A filteredset is heavily used, but it cannot provide a printable information
how given set is filtered because a condition is an arbitrary callable object.

This patch adds an optional "condrepr" object that is used only by repr(). To
minimize the maintaining/runtime overhead of "condrepr", its type is overloaded
as follows:

  type      example
  --------  ---------------------------------
  tuple     ('<not %r>', other)
  str       '<branch closed>'
  callable  lambda: '<branch %r>' % sorted(b)
  object    other
Pierre-Yves David - March 9, 2016, 6:15 p.m.
On 02/28/2016 06:38 AM, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1455359111 -32400
> #      Sat Feb 13 19:25:11 2016 +0900
> # Node ID f8df065a49aecbc9b78869c38890ba2cce6afaa6
> # Parent  10eaae94523c790d7b77c52a4cb4bfcf406021ef
> revset: add extra data to filteredset for better inspection

Pushed to the clowncopter, thanks.

Patch

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -2759,6 +2759,29 @@  def funcsused(tree):
             funcs.add(tree[1][1])
         return funcs
 
+def _formatsetrepr(r):
+    """Format an optional printable representation of a set
+
+    ========  =================================
+    type(r)   example
+    ========  =================================
+    tuple     ('<not %r>', other)
+    str       '<branch closed>'
+    callable  lambda: '<branch %r>' % sorted(b)
+    object    other
+    ========  =================================
+    """
+    if r is None:
+        return ''
+    elif isinstance(r, tuple):
+        return r[0] % r[1:]
+    elif isinstance(r, str):
+        return r
+    elif callable(r):
+        return r()
+    else:
+        return repr(r)
+
 class abstractsmartset(object):
 
     def __nonzero__(self):
@@ -2839,7 +2862,7 @@  class abstractsmartset(object):
         This is part of the mandatory API for smartset."""
         if isinstance(other, fullreposet):
             return self
-        return self.filter(other.__contains__, cache=False)
+        return self.filter(other.__contains__, condrepr=other, cache=False)
 
     def __add__(self, other):
         """Returns a new object with the union of the two collections.
@@ -2852,19 +2875,21 @@  class abstractsmartset(object):
 
         This is part of the mandatory API for smartset."""
         c = other.__contains__
-        return self.filter(lambda r: not c(r), cache=False)
-
-    def filter(self, condition, cache=True):
+        return self.filter(lambda r: not c(r), condrepr=('<not %r>', other),
+                           cache=False)
+
+    def filter(self, condition, condrepr=None, cache=True):
         """Returns this smartset filtered by condition as a new smartset.
 
         `condition` is a callable which takes a revision number and returns a
-        boolean.
+        boolean. Optional `condrepr` provides a printable representation of
+        the given `condition`.
 
         This is part of the mandatory API for smartset."""
         # builtin cannot be cached. but do not needs to
         if cache and util.safehasattr(condition, 'func_code'):
             condition = util.cachefunc(condition)
-        return filteredset(self, condition)
+        return filteredset(self, condition, condrepr)
 
 class baseset(abstractsmartset):
     """Basic data structure that represents a revset and contains the basic
@@ -2968,13 +2993,16 @@  class filteredset(abstractsmartset):
     the subset and contains a function which tests for membership in the
     revset
     """
-    def __init__(self, subset, condition=lambda x: True):
+    def __init__(self, subset, condition=lambda x: True, condrepr=None):
         """
         condition: a function that decide whether a revision in the subset
                    belongs to the revset or not.
+        condrepr: a tuple of (format, obj, ...), a function or an object that
+                  provides a printable representation of the given condition.
         """
         self._subset = subset
         self._condition = condition
+        self._condrepr = condrepr
 
     def __contains__(self, x):
         return x in self._subset and self._condition(x)
@@ -3054,7 +3082,11 @@  class filteredset(abstractsmartset):
             return x
 
     def __repr__(self):
-        return '<%s %r>' % (type(self).__name__, self._subset)
+        xs = [repr(self._subset)]
+        s = _formatsetrepr(self._condrepr)
+        if s:
+            xs.append(s)
+        return '<%s %s>' % (type(self).__name__, ', '.join(xs))
 
 def _iterordered(ascending, iter1, iter2):
     """produce an ordered iteration from two iterators with the same order
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -169,7 +169,9 @@  names that should work without quoting
     ('symbol', 'a'))
   * set:
   <filteredset
-    <baseset [1]>>
+    <baseset [1]>,
+    <not
+      <baseset [0]>>>
   1
   $ try _a_b_c_
   ('symbol', '_a_b_c_')
@@ -182,7 +184,9 @@  names that should work without quoting
     ('symbol', 'a'))
   * set:
   <filteredset
-    <baseset [6]>>
+    <baseset [6]>,
+    <not
+      <baseset [0]>>>
   6
   $ try .a.b.c.
   ('symbol', '.a.b.c.')
@@ -195,7 +199,9 @@  names that should work without quoting
     ('symbol', 'a'))
   * set:
   <filteredset
-    <baseset [7]>>
+    <baseset [7]>,
+    <not
+      <baseset [0]>>>
   7
 
 names that should be caught by fallback mechanism
@@ -278,7 +284,9 @@  quoting needed
     ('symbol', 'a'))
   * set:
   <filteredset
-    <baseset [4]>>
+    <baseset [4]>,
+    <not
+      <baseset [0]>>>
   4
 
   $ log '1 or 2'