diff options
author | Pierre-Yves David <pierre-yves.david@logilab.fr> | 2008-06-24 11:59:16 +0200 |
---|---|---|
committer | Pierre-Yves David <pierre-yves.david@logilab.fr> | 2008-06-24 11:59:16 +0200 |
commit | 6af087a3c32ac501f742d6dd1a74848175188d79 (patch) | |
tree | 370773b886753eaff75b1d28b820a6c432e955be | |
parent | 156df98848bcc383fd126d7649d45410f975ecca (diff) | |
download | logilab-common-6af087a3c32ac501f742d6dd1a74848175188d79.tar.gz |
compat: adds a max function taking 'key' as keyword argument
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | compat.py | 40 | ||||
-rw-r--r-- | test/unittest_compat.py | 38 |
3 files changed, 78 insertions, 1 deletions
@@ -10,6 +10,7 @@ ChangeLog for logilab.common - added assertUnorderedIterableEquals * umessage.date() return unparsage string as is instead of None + * compat: adds a max function taking 'key' as keyword argument 2008-09-08 -- 0.32.0 * textutils: add the apply_unit fonction * testlib: @@ -22,6 +22,8 @@ from __future__ import generators from warnings import warn +import __builtin__ + from logilab.common.deprecation import class_renamed try: @@ -188,6 +190,44 @@ except NameError: l2.reverse() return l2 +try: # + max = max + max(("ab","cde"),key=len) +except TypeError: + def max( *args, **kargs): + if len(args) == 0: + raise TypeError("max expected at least 1 arguments, got 0") + key= kargs.pop("key", None) + #default implementation + if key is None: + return __builtin__.max(*args,**kargs) + + for karg in kargs: + raise TypeError("unexpected keyword argument %s for function max") % karg + + if len(args) == 1: + items = iter(args[0]) + else: + items = iter(args) + + try: + best_item = items.next() + best_value = key(best_item) + except StopIteration: + raise ValueError("max() arg is an empty sequence") + + for item in items: + value = key(item) + if value > best_value: + best_item = item + best_value = value + + return best_item + + + + + # Python2.5 builtins try: any = any diff --git a/test/unittest_compat.py b/test/unittest_compat.py index b9c7cd0..eaa769b 100644 --- a/test/unittest_compat.py +++ b/test/unittest_compat.py @@ -9,11 +9,13 @@ import pprint class CompatTCMixIn: MODNAMES = {} BUILTINS = [] + ALTERED_BUILTINS = {} def setUp(self): self.builtins_backup = {} self.modules_backup = {} self.remove_builtins() + self.alter_builtins() self.remove_modules() def tearDown(self): @@ -36,6 +38,13 @@ class CompatTCMixIn: self.builtins_backup[builtin] = func delattr(__builtin__, builtin) # setattr(__builtin__, 'builtin_%s' % builtin, func) + def alter_builtins(self): + for builtin, func in self.ALTERED_BUILTINS.iteritems(): + old_func = getattr(__builtin__, builtin, None) + if func is not None: + self.builtins_backup[builtin] = old_func + setattr(__builtin__, builtin, func) + # setattr(__builtin__, 'builtin_%s' % builtin, func) def remove_modules(self): for modname in self.MODNAMES: @@ -147,9 +156,18 @@ class Py24CompatTC(CompatTCMixIn, TestCase): +class _MaxFaker(object): + def __init__(self, func): + self.func = func + def fake(self,*args,**kargs): + if kargs: + raise TypeError("max() takes no keyword argument") + return self.func(*args) + class Py25CompatTC(CompatTCMixIn, TestCase): BUILTINS = ('any', 'all',) + ALTERED_BUILTINS = {'max': _MaxFaker(max).fake} def test_any(self): from logilab.common.compat import any @@ -180,7 +198,25 @@ class Py25CompatTC(CompatTCMixIn, TestCase): self.assertEquals(all(irange), False) self.assertEquals(irange.next(), 1) - + def test_max(self): + from logilab.common.compat import max + + # old apy + self.assertEquals(max("fdjkmhsgmdfhsg"),'s') + self.assertEquals(max(1,43,12,45,1337,34,2), 1337) + self.assertRaises(TypeError,max) + self.assertRaises(TypeError,max,1) + self.assertRaises(ValueError,max,[]) + self.assertRaises(TypeError,max,bob=None) + + # new apy + self.assertEquals(max("shorter","longer",key=len),"shorter") + self.assertEquals(max(((1,1),(2,3,5),(8,13,21)),key=len),(2,3,5)) + self.assertEquals(max(((1,1),(42,),(2,3,5),(8,13,21)),key=max),(42,)) + self.assertRaises(TypeError,max,key=None) + self.assertRaises(TypeError,max,1,key=len) + self.assertRaises(ValueError,max,[],key=max) + self.assertRaises(TypeError,max,"shorter","longer",key=len,kathy=None) if __name__ == '__main__': unittest_main() |