Mercurial > public > mercurial-scm > hg
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. |