comparison mercurial/revset.py @ 28423:0d79d91ba7e3

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
author Yuya Nishihara <yuya@tcha.org>
date Sat, 13 Feb 2016 19:25:11 +0900
parents 0383f7a5e86c
children 534f968d33e5
comparison
equal deleted inserted replaced
28422:e2c6092ad422 28423:0d79d91ba7e3
2728 funcs |= funcsused(s) 2728 funcs |= funcsused(s)
2729 if tree[0] == 'func': 2729 if tree[0] == 'func':
2730 funcs.add(tree[1][1]) 2730 funcs.add(tree[1][1])
2731 return funcs 2731 return funcs
2732 2732
2733 def _formatsetrepr(r):
2734 """Format an optional printable representation of a set
2735
2736 ======== =================================
2737 type(r) example
2738 ======== =================================
2739 tuple ('<not %r>', other)
2740 str '<branch closed>'
2741 callable lambda: '<branch %r>' % sorted(b)
2742 object other
2743 ======== =================================
2744 """
2745 if r is None:
2746 return ''
2747 elif isinstance(r, tuple):
2748 return r[0] % r[1:]
2749 elif isinstance(r, str):
2750 return r
2751 elif callable(r):
2752 return r()
2753 else:
2754 return repr(r)
2755
2733 class abstractsmartset(object): 2756 class abstractsmartset(object):
2734 2757
2735 def __nonzero__(self): 2758 def __nonzero__(self):
2736 """True if the smartset is not empty""" 2759 """True if the smartset is not empty"""
2737 raise NotImplementedError() 2760 raise NotImplementedError()
2808 """Returns a new object with the intersection of the two collections. 2831 """Returns a new object with the intersection of the two collections.
2809 2832
2810 This is part of the mandatory API for smartset.""" 2833 This is part of the mandatory API for smartset."""
2811 if isinstance(other, fullreposet): 2834 if isinstance(other, fullreposet):
2812 return self 2835 return self
2813 return self.filter(other.__contains__, cache=False) 2836 return self.filter(other.__contains__, condrepr=other, cache=False)
2814 2837
2815 def __add__(self, other): 2838 def __add__(self, other):
2816 """Returns a new object with the union of the two collections. 2839 """Returns a new object with the union of the two collections.
2817 2840
2818 This is part of the mandatory API for smartset.""" 2841 This is part of the mandatory API for smartset."""
2821 def __sub__(self, other): 2844 def __sub__(self, other):
2822 """Returns a new object with the substraction of the two collections. 2845 """Returns a new object with the substraction of the two collections.
2823 2846
2824 This is part of the mandatory API for smartset.""" 2847 This is part of the mandatory API for smartset."""
2825 c = other.__contains__ 2848 c = other.__contains__
2826 return self.filter(lambda r: not c(r), cache=False) 2849 return self.filter(lambda r: not c(r), condrepr=('<not %r>', other),
2827 2850 cache=False)
2828 def filter(self, condition, cache=True): 2851
2852 def filter(self, condition, condrepr=None, cache=True):
2829 """Returns this smartset filtered by condition as a new smartset. 2853 """Returns this smartset filtered by condition as a new smartset.
2830 2854
2831 `condition` is a callable which takes a revision number and returns a 2855 `condition` is a callable which takes a revision number and returns a
2832 boolean. 2856 boolean. Optional `condrepr` provides a printable representation of
2857 the given `condition`.
2833 2858
2834 This is part of the mandatory API for smartset.""" 2859 This is part of the mandatory API for smartset."""
2835 # builtin cannot be cached. but do not needs to 2860 # builtin cannot be cached. but do not needs to
2836 if cache and util.safehasattr(condition, 'func_code'): 2861 if cache and util.safehasattr(condition, 'func_code'):
2837 condition = util.cachefunc(condition) 2862 condition = util.cachefunc(condition)
2838 return filteredset(self, condition) 2863 return filteredset(self, condition, condrepr)
2839 2864
2840 class baseset(abstractsmartset): 2865 class baseset(abstractsmartset):
2841 """Basic data structure that represents a revset and contains the basic 2866 """Basic data structure that represents a revset and contains the basic
2842 operation that it should be able to perform. 2867 operation that it should be able to perform.
2843 2868
2937 class filteredset(abstractsmartset): 2962 class filteredset(abstractsmartset):
2938 """Duck type for baseset class which iterates lazily over the revisions in 2963 """Duck type for baseset class which iterates lazily over the revisions in
2939 the subset and contains a function which tests for membership in the 2964 the subset and contains a function which tests for membership in the
2940 revset 2965 revset
2941 """ 2966 """
2942 def __init__(self, subset, condition=lambda x: True): 2967 def __init__(self, subset, condition=lambda x: True, condrepr=None):
2943 """ 2968 """
2944 condition: a function that decide whether a revision in the subset 2969 condition: a function that decide whether a revision in the subset
2945 belongs to the revset or not. 2970 belongs to the revset or not.
2971 condrepr: a tuple of (format, obj, ...), a function or an object that
2972 provides a printable representation of the given condition.
2946 """ 2973 """
2947 self._subset = subset 2974 self._subset = subset
2948 self._condition = condition 2975 self._condition = condition
2976 self._condrepr = condrepr
2949 2977
2950 def __contains__(self, x): 2978 def __contains__(self, x):
2951 return x in self._subset and self._condition(x) 2979 return x in self._subset and self._condition(x)
2952 2980
2953 def __iter__(self): 2981 def __iter__(self):
3023 for x in self: 3051 for x in self:
3024 pass 3052 pass
3025 return x 3053 return x
3026 3054
3027 def __repr__(self): 3055 def __repr__(self):
3028 return '<%s %r>' % (type(self).__name__, self._subset) 3056 xs = [repr(self._subset)]
3057 s = _formatsetrepr(self._condrepr)
3058 if s:
3059 xs.append(s)
3060 return '<%s %s>' % (type(self).__name__, ', '.join(xs))
3029 3061
3030 def _iterordered(ascending, iter1, iter2): 3062 def _iterordered(ascending, iter1, iter2):
3031 """produce an ordered iteration from two iterators with the same order 3063 """produce an ordered iteration from two iterators with the same order
3032 3064
3033 The ascending is used to indicated the iteration direction. 3065 The ascending is used to indicated the iteration direction.