comparison mercurial/templateutil.py @ 38267:fb874fc1d9b4

templater: abstract ifcontains() over wrapped types This allows us to make .keytype private. There's a minor BC that a hybrid dict/list of keytype=None now strictly checks the type of the needle. For example, {ifcontains(rev, files)} no longer matches a file named "1" at the rev=1. I made this change for consistency with the get(dict, key) function. We can restore the old behavior by making keytype=bytes the default if desired.
author Yuya Nishihara <yuya@tcha.org>
date Mon, 19 Mar 2018 00:23:20 +0900
parents 80f423a14c90
children 49ef1539b84e
comparison
equal deleted inserted replaced
38266:80f423a14c90 38267:fb874fc1d9b4
36 """ 36 """
37 37
38 __metaclass__ = abc.ABCMeta 38 __metaclass__ = abc.ABCMeta
39 39
40 @abc.abstractmethod 40 @abc.abstractmethod
41 def contains(self, context, mapping, item):
42 """Test if the specified item is in self
43
44 The item argument may be a wrapped object.
45 """
46
47 @abc.abstractmethod
41 def getmember(self, context, mapping, key): 48 def getmember(self, context, mapping, key):
42 """Return a member item for the specified key 49 """Return a member item for the specified key
43 50
44 The key argument may be a wrapped object. 51 The key argument may be a wrapped object.
45 A returned object may be either a wrapped object or a pure value 52 A returned object may be either a wrapped object or a pure value
89 """Wrapper for byte string""" 96 """Wrapper for byte string"""
90 97
91 def __init__(self, value): 98 def __init__(self, value):
92 self._value = value 99 self._value = value
93 100
101 def contains(self, context, mapping, item):
102 item = stringify(context, mapping, item)
103 return item in self._value
104
94 def getmember(self, context, mapping, key): 105 def getmember(self, context, mapping, key):
95 raise error.ParseError(_('%r is not a dictionary') 106 raise error.ParseError(_('%r is not a dictionary')
96 % pycompat.bytestr(self._value)) 107 % pycompat.bytestr(self._value))
97 108
98 def getmin(self, context, mapping): 109 def getmin(self, context, mapping):
122 class wrappedvalue(wrapped): 133 class wrappedvalue(wrapped):
123 """Generic wrapper for pure non-list/dict/bytes value""" 134 """Generic wrapper for pure non-list/dict/bytes value"""
124 135
125 def __init__(self, value): 136 def __init__(self, value):
126 self._value = value 137 self._value = value
138
139 def contains(self, context, mapping, item):
140 raise error.ParseError(_("%r is not iterable") % self._value)
127 141
128 def getmember(self, context, mapping, key): 142 def getmember(self, context, mapping, key):
129 raise error.ParseError(_('%r is not a dictionary') % self._value) 143 raise error.ParseError(_('%r is not a dictionary') % self._value)
130 144
131 def getmin(self, context, mapping): 145 def getmin(self, context, mapping):
168 self._gen = gen # generator or function returning generator 182 self._gen = gen # generator or function returning generator
169 self._values = values 183 self._values = values
170 self._makemap = makemap 184 self._makemap = makemap
171 self._joinfmt = joinfmt 185 self._joinfmt = joinfmt
172 self.keytype = keytype # hint for 'x in y' where type(x) is unresolved 186 self.keytype = keytype # hint for 'x in y' where type(x) is unresolved
187
188 def contains(self, context, mapping, item):
189 item = unwrapastype(context, mapping, item, self.keytype)
190 return item in self._values
173 191
174 def getmember(self, context, mapping, key): 192 def getmember(self, context, mapping, key):
175 # TODO: maybe split hybrid list/dict types? 193 # TODO: maybe split hybrid list/dict types?
176 if not util.safehasattr(self._values, 'get'): 194 if not util.safehasattr(self._values, 'get'):
177 raise error.ParseError(_('not a dictionary')) 195 raise error.ParseError(_('not a dictionary'))
253 self._makemap = makemap 271 self._makemap = makemap
254 272
255 def tomap(self): 273 def tomap(self):
256 return self._makemap(self._key) 274 return self._makemap(self._key)
257 275
276 def contains(self, context, mapping, item):
277 w = makewrapped(context, mapping, self._value)
278 return w.contains(context, mapping, item)
279
258 def getmember(self, context, mapping, key): 280 def getmember(self, context, mapping, key):
259 w = makewrapped(context, mapping, self._value) 281 w = makewrapped(context, mapping, self._value)
260 return w.getmember(context, mapping, key) 282 return w.getmember(context, mapping, key)
261 283
262 def getmin(self, context, mapping): 284 def getmin(self, context, mapping):
299 if name is not None and tmpl is not None: 321 if name is not None and tmpl is not None:
300 raise error.ProgrammingError('name and tmpl are mutually exclusive') 322 raise error.ProgrammingError('name and tmpl are mutually exclusive')
301 self._name = name 323 self._name = name
302 self._tmpl = tmpl 324 self._tmpl = tmpl
303 self._defaultsep = sep 325 self._defaultsep = sep
326
327 def contains(self, context, mapping, item):
328 raise error.ParseError(_('not comparable'))
304 329
305 def getmember(self, context, mapping, key): 330 def getmember(self, context, mapping, key):
306 raise error.ParseError(_('not a dictionary')) 331 raise error.ParseError(_('not a dictionary'))
307 332
308 def getmin(self, context, mapping): 333 def getmin(self, context, mapping):
368 """ 393 """
369 394
370 def __init__(self, make, args=()): 395 def __init__(self, make, args=()):
371 self._make = make 396 self._make = make
372 self._args = args 397 self._args = args
398
399 def contains(self, context, mapping, item):
400 item = stringify(context, mapping, item)
401 return item in self.tovalue(context, mapping)
373 402
374 def _gen(self, context): 403 def _gen(self, context):
375 return self._make(context, *self._args) 404 return self._make(context, *self._args)
376 405
377 def getmember(self, context, mapping, key): 406 def getmember(self, context, mapping, key):