Show More
@@ -1,99 +1,109 b'' | |||||
1 | """This is version 0.7 of Philip J. Eby's simplegeneric module |
|
1 | """This is version 0.7 of Philip J. Eby's simplegeneric module | |
2 | (http://pypi.python.org/pypi/simplegeneric) |
|
2 | (http://pypi.python.org/pypi/simplegeneric), patched to work with Python 3, | |
|
3 | which doesn't support old-style classes. | |||
3 | """ |
|
4 | """ | |
4 |
|
5 | |||
5 | #Name: simplegeneric |
|
6 | #Name: simplegeneric | |
6 | #Version: 0.7 |
|
7 | #Version: 0.7 | |
7 | #Summary: Simple generic functions (similar to Python's own len(), pickle.dump(), etc.) |
|
8 | #Summary: Simple generic functions (similar to Python's own len(), pickle.dump(), etc.) | |
8 | #Home-page: http://pypi.python.org/pypi/simplegeneric |
|
9 | #Home-page: http://pypi.python.org/pypi/simplegeneric | |
9 | #Author: Phillip J. Eby |
|
10 | #Author: Phillip J. Eby | |
10 | #Author-email: peak@eby-sarna.com |
|
11 | #Author-email: peak@eby-sarna.com | |
11 | #License: PSF or ZPL |
|
12 | #License: PSF or ZPL | |
12 |
|
13 | |||
13 | __all__ = ["generic"] |
|
14 | __all__ = ["generic"] | |
14 |
|
15 | |||
15 | from types import ClassType, InstanceType |
|
16 | try: | |
16 | classtypes = type, ClassType |
|
17 | from types import ClassType, InstanceType | |
|
18 | except ImportError: | |||
|
19 | classtypes = type | |||
|
20 | else: | |||
|
21 | classtypes = type, ClassType | |||
17 |
|
22 | |||
18 | def generic(func): |
|
23 | def generic(func): | |
19 | """Create a simple generic function""" |
|
24 | """Create a simple generic function""" | |
20 |
|
25 | |||
21 | _sentinel = object() |
|
26 | _sentinel = object() | |
22 |
|
27 | |||
23 | def _by_class(*args, **kw): |
|
28 | def _by_class(*args, **kw): | |
24 | cls = args[0].__class__ |
|
29 | cls = args[0].__class__ | |
25 | for t in type(cls.__name__, (cls,object), {}).__mro__: |
|
30 | for t in type(cls.__name__, (cls,object), {}).__mro__: | |
26 | f = _gbt(t, _sentinel) |
|
31 | f = _gbt(t, _sentinel) | |
27 | if f is not _sentinel: |
|
32 | if f is not _sentinel: | |
28 | return f(*args, **kw) |
|
33 | return f(*args, **kw) | |
29 | else: |
|
34 | else: | |
30 | return func(*args, **kw) |
|
35 | return func(*args, **kw) | |
31 |
|
36 | |||
32 |
_by_type = {object: func |
|
37 | _by_type = {object: func} | |
|
38 | try: | |||
|
39 | _by_type[InstanceType] = _by_class | |||
|
40 | except NameError: # Python 3 | |||
|
41 | pass | |||
|
42 | ||||
33 | _gbt = _by_type.get |
|
43 | _gbt = _by_type.get | |
34 |
|
44 | |||
35 | def when_type(*types): |
|
45 | def when_type(*types): | |
36 | """Decorator to add a method that will be called for the given types""" |
|
46 | """Decorator to add a method that will be called for the given types""" | |
37 | for t in types: |
|
47 | for t in types: | |
38 | if not isinstance(t, classtypes): |
|
48 | if not isinstance(t, classtypes): | |
39 | raise TypeError( |
|
49 | raise TypeError( | |
40 | "%r is not a type or class" % (t,) |
|
50 | "%r is not a type or class" % (t,) | |
41 | ) |
|
51 | ) | |
42 | def decorate(f): |
|
52 | def decorate(f): | |
43 | for t in types: |
|
53 | for t in types: | |
44 | if _by_type.setdefault(t,f) is not f: |
|
54 | if _by_type.setdefault(t,f) is not f: | |
45 | raise TypeError( |
|
55 | raise TypeError( | |
46 | "%r already has method for type %r" % (func, t) |
|
56 | "%r already has method for type %r" % (func, t) | |
47 | ) |
|
57 | ) | |
48 | return f |
|
58 | return f | |
49 | return decorate |
|
59 | return decorate | |
50 |
|
60 | |||
51 |
|
61 | |||
52 |
|
62 | |||
53 |
|
63 | |||
54 | _by_object = {} |
|
64 | _by_object = {} | |
55 | _gbo = _by_object.get |
|
65 | _gbo = _by_object.get | |
56 |
|
66 | |||
57 | def when_object(*obs): |
|
67 | def when_object(*obs): | |
58 | """Decorator to add a method to be called for the given object(s)""" |
|
68 | """Decorator to add a method to be called for the given object(s)""" | |
59 | def decorate(f): |
|
69 | def decorate(f): | |
60 | for o in obs: |
|
70 | for o in obs: | |
61 | if _by_object.setdefault(id(o), (o,f))[1] is not f: |
|
71 | if _by_object.setdefault(id(o), (o,f))[1] is not f: | |
62 | raise TypeError( |
|
72 | raise TypeError( | |
63 | "%r already has method for object %r" % (func, o) |
|
73 | "%r already has method for object %r" % (func, o) | |
64 | ) |
|
74 | ) | |
65 | return f |
|
75 | return f | |
66 | return decorate |
|
76 | return decorate | |
67 |
|
77 | |||
68 |
|
78 | |||
69 | def dispatch(*args, **kw): |
|
79 | def dispatch(*args, **kw): | |
70 | f = _gbo(id(args[0]), _sentinel) |
|
80 | f = _gbo(id(args[0]), _sentinel) | |
71 | if f is _sentinel: |
|
81 | if f is _sentinel: | |
72 | for t in type(args[0]).__mro__: |
|
82 | for t in type(args[0]).__mro__: | |
73 | f = _gbt(t, _sentinel) |
|
83 | f = _gbt(t, _sentinel) | |
74 | if f is not _sentinel: |
|
84 | if f is not _sentinel: | |
75 | return f(*args, **kw) |
|
85 | return f(*args, **kw) | |
76 | else: |
|
86 | else: | |
77 | return func(*args, **kw) |
|
87 | return func(*args, **kw) | |
78 | else: |
|
88 | else: | |
79 | return f[1](*args, **kw) |
|
89 | return f[1](*args, **kw) | |
80 |
|
90 | |||
81 | dispatch.__name__ = func.__name__ |
|
91 | dispatch.__name__ = func.__name__ | |
82 | dispatch.__dict__ = func.__dict__.copy() |
|
92 | dispatch.__dict__ = func.__dict__.copy() | |
83 | dispatch.__doc__ = func.__doc__ |
|
93 | dispatch.__doc__ = func.__doc__ | |
84 | dispatch.__module__ = func.__module__ |
|
94 | dispatch.__module__ = func.__module__ | |
85 |
|
95 | |||
86 | dispatch.when_type = when_type |
|
96 | dispatch.when_type = when_type | |
87 | dispatch.when_object = when_object |
|
97 | dispatch.when_object = when_object | |
88 | dispatch.default = func |
|
98 | dispatch.default = func | |
89 | dispatch.has_object = lambda o: id(o) in _by_object |
|
99 | dispatch.has_object = lambda o: id(o) in _by_object | |
90 | dispatch.has_type = lambda t: t in _by_type |
|
100 | dispatch.has_type = lambda t: t in _by_type | |
91 | return dispatch |
|
101 | return dispatch | |
92 |
|
102 | |||
93 |
|
103 | |||
94 | def test_suite(): |
|
104 | def test_suite(): | |
95 | import doctest |
|
105 | import doctest | |
96 | return doctest.DocFileSuite( |
|
106 | return doctest.DocFileSuite( | |
97 | 'README.txt', |
|
107 | 'README.txt', | |
98 | optionflags=doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE, |
|
108 | optionflags=doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE, | |
99 | ) |
|
109 | ) |
General Comments 0
You need to be logged in to leave comments.
Login now