comparison roundup/cgi/templating.py @ 5414:3fa026621f69

Python 3 preparation: comparisons. Python 3 no longer has the cmp function, or cmp= arguments to sorting functions / methods (key= must be used instead), and requires rich comparison methods such as __lt__ to be defined instead of using __cmp__. All of the comparison mechanisms supported in Python 3 are also supported in Python 2. This patch makes the corresponding changes in Roundup to use key functions and rich comparison methods. In the case of the JournalPassword and Permission classes, only __eq__ and __ne__ are defined as I don't see ordered comparisons as useful there (and for Permission, the old __cmp__ function didn't try to provide a valid ordering). In the case of the Date class, I kept the __cmp__ method and implemented the others in terms of it, to avoid excess repetitiveness in duplicating implementation code for all six rich comparison methods. In roundup/admin.py, help_commands_html used operator.attrgetter to produce the second argument of sorted() - which would be reasonable for a key function, but the second argument is the cmp function in Python 2, not a key function (and the key function must be a named argument not a positional argument in Python 3). That function appears to be completely unused, so I expect that code never worked. This patch adds the missing key= to that sorted() call, but it would also be reasonable to remove the unused function completely instead.
author Joseph Myers <jsm@polyomino.org.uk>
date Wed, 25 Jul 2018 00:39:37 +0000
parents 3757449e00c4
children 56c9bcdea47f
comparison
equal deleted inserted replaced
5413:7a41dd2abbbd 5414:3fa026621f69
618 if isinstance(prop, klass): 618 if isinstance(prop, klass):
619 value = prop.get_default_value() 619 value = prop.get_default_value()
620 l.append(htmlklass(self._client, self._classname, '', 620 l.append(htmlklass(self._client, self._classname, '',
621 prop, name, value, self._anonymous)) 621 prop, name, value, self._anonymous))
622 if sort: 622 if sort:
623 l.sort(lambda a,b:cmp(a._name, b._name)) 623 l.sort(key=lambda a:a._name)
624 return l 624 return l
625 625
626 def list(self, sort_on=None): 626 def list(self, sort_on=None):
627 """ List all items in this class. 627 """ List all items in this class.
628 """ 628 """
629 # get the list and sort it nicely 629 # get the list and sort it nicely
630 l = self._klass.list() 630 l = self._klass.list()
631 sortfunc = make_sort_function(self._db, self._classname, sort_on) 631 keyfunc = make_key_function(self._db, self._classname, sort_on)
632 l.sort(sortfunc) 632 l.sort(key=keyfunc)
633 633
634 # check perms 634 # check perms
635 check = self._client.db.security.hasPermission 635 check = self._client.db.security.hasPermission
636 userid = self._client.userid 636 userid = self._client.userid
637 if not check('Web Access', userid): 637 if not check('Web Access', userid):
1336 classname = self.__class__.__name__ 1336 classname = self.__class__.__name__
1337 return '<%s(0x%x) %s %r %r>'%(classname, id(self), self._formname, 1337 return '<%s(0x%x) %s %r %r>'%(classname, id(self), self._formname,
1338 self._prop, self._value) 1338 self._prop, self._value)
1339 def __str__(self): 1339 def __str__(self):
1340 return self.plain() 1340 return self.plain()
1341 def __cmp__(self, other): 1341 def __lt__(self, other):
1342 if isinstance(other, HTMLProperty): 1342 if isinstance(other, HTMLProperty):
1343 return cmp(self._value, other._value) 1343 return self._value < other._value
1344 return cmp(self._value, other) 1344 return self._value < other
1345 def __le__(self, other):
1346 if isinstance(other, HTMLProperty):
1347 return self._value <= other._value
1348 return self._value <= other
1349 def __eq__(self, other):
1350 if isinstance(other, HTMLProperty):
1351 return self._value == other._value
1352 return self._value == other
1353 def __ne__(self, other):
1354 if isinstance(other, HTMLProperty):
1355 return self._value != other._value
1356 return self._value != other
1357 def __gt__(self, other):
1358 if isinstance(other, HTMLProperty):
1359 return self._value > other._value
1360 return self._value > other
1361 def __ge__(self, other):
1362 if isinstance(other, HTMLProperty):
1363 return self._value >= other._value
1364 return self._value >= other
1345 1365
1346 def __bool__(self): 1366 def __bool__(self):
1347 return not not self._value 1367 return not not self._value
1348 # Python 2 compatibility: 1368 # Python 2 compatibility:
1349 __nonzero__ = __bool__ 1369 __nonzero__ = __bool__
2256 def __init__(self, *args, **kwargs): 2276 def __init__(self, *args, **kwargs):
2257 HTMLProperty.__init__(self, *args, **kwargs) 2277 HTMLProperty.__init__(self, *args, **kwargs)
2258 if self._value: 2278 if self._value:
2259 display_value = lookupIds(self._db, self._prop, self._value, 2279 display_value = lookupIds(self._db, self._prop, self._value,
2260 fail_ok=1, do_lookup=False) 2280 fail_ok=1, do_lookup=False)
2261 sortfun = make_sort_function(self._db, self._prop.classname) 2281 keyfun = make_key_function(self._db, self._prop.classname)
2262 # sorting fails if the value contains 2282 # sorting fails if the value contains
2263 # items not yet stored in the database 2283 # items not yet stored in the database
2264 # ignore these errors to preserve user input 2284 # ignore these errors to preserve user input
2265 try: 2285 try:
2266 display_value.sort(sortfun) 2286 display_value.sort(key=keyfun)
2267 except: 2287 except:
2268 pass 2288 pass
2269 self._value = display_value 2289 self._value = display_value
2270 2290
2271 def __len__(self): 2291 def __len__(self):
2301 return self.viewableGenerator(l) 2321 return self.viewableGenerator(l)
2302 2322
2303 def sorted(self, property): 2323 def sorted(self, property):
2304 """ Return this multilink sorted by the given property """ 2324 """ Return this multilink sorted by the given property """
2305 value = list(self.__iter__()) 2325 value = list(self.__iter__())
2306 value.sort(lambda a,b:cmp(a[property], b[property])) 2326 value.sort(key=lambda a:a[property])
2307 return value 2327 return value
2308 2328
2309 def __contains__(self, value): 2329 def __contains__(self, value):
2310 """ Support the "in" operator. We have to make sure the passed-in 2330 """ Support the "in" operator. We have to make sure the passed-in
2311 value is a string first, not a HTMLProperty. 2331 value is a string first, not a HTMLProperty.
2499 break 2519 break
2500 else: 2520 else:
2501 propclasses.append((prop, cls)) 2521 propclasses.append((prop, cls))
2502 2522
2503 2523
2504 def make_sort_function(db, classname, sort_on=None): 2524 def make_key_function(db, classname, sort_on=None):
2505 """Make a sort function for a given class. 2525 """Make a sort key function for a given class.
2506 2526
2507 The list being sorted may contain mixed ids and labels. 2527 The list being sorted may contain mixed ids and labels.
2508 """ 2528 """
2509 linkcl = db.getclass(classname) 2529 linkcl = db.getclass(classname)
2510 if sort_on is None: 2530 if sort_on is None:
2511 sort_on = linkcl.orderprop() 2531 sort_on = linkcl.orderprop()
2512 def sortfunc(a, b): 2532 def keyfunc(a):
2513 if num_re.match(a): 2533 if num_re.match(a):
2514 a = linkcl.get(a, sort_on) 2534 a = linkcl.get(a, sort_on)
2515 if num_re.match(b): 2535 return a
2516 b = linkcl.get(b, sort_on) 2536 return keyfunc
2517 return cmp(a, b)
2518 return sortfunc
2519 2537
2520 def handleListCGIValue(value): 2538 def handleListCGIValue(value):
2521 """ Value is either a single item or a list of items. Each item has a 2539 """ Value is either a single item or a list of items. Each item has a
2522 .value that we're actually interested in. 2540 .value that we're actually interested in.
2523 """ 2541 """

Roundup Issue Tracker: http://roundup-tracker.org/