[PATCH 3 of 7] revset: add extra data to filteredset for better inspection

Yuya Nishihara yuya at tcha.org
Sat Feb 27 09:38:17 EST 2016


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1455359111 -32400
#      Sat Feb 13 19:25:11 2016 +0900
# Node ID 254f83b3fd6cd28a0648d89ed5815d1a75b30242
# Parent  fe9925d9c774eec6d1ccaeddc05dc287b572ef6e
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
  --------  ---------------------------------
  str       '<branch closed>'
  tuple     ('<not %r>', other)
  callable  lambda: '<branch %r>' % sorted(b)
  object    other

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -2759,6 +2759,18 @@ def funcsused(tree):
             funcs.add(tree[1][1])
         return funcs
 
+def _formatsetrepr(r):
+    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 +2851,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 +2864,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 +2982,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 +3071,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'


More information about the Mercurial-devel mailing list