blob: b0bbfc1b4a0fe83a3fa23b2b10528597be0181ef [file] [log] [blame]
Georg Brandle5a32dc2007-12-21 08:16:54 +00001"""
2Define names for built-in types that aren't directly accessible as a builtin.
Guido van Rossume7b146f2000-02-04 15:28:42 +00003"""
Guido van Rossum85d89451994-06-23 11:53:27 +00004import sys
5
Tim Peters26991a72001-09-25 22:02:03 +00006# Iterators in Python aren't a matter of type but of protocol. A large
7# and changing number of builtin types implement *some* flavor of
8# iterator. Don't check the type! Use hasattr to check for both
Georg Brandla18af4e2007-04-21 15:47:16 +00009# "__iter__" and "__next__" attributes instead.
Tim Peters26991a72001-09-25 22:02:03 +000010
Guido van Rossumadc940e1994-09-29 10:04:43 +000011def _f(): pass
12FunctionType = type(_f)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000013LambdaType = type(lambda: None) # Same as FunctionType
Guido van Rossuma8add0e2007-05-14 22:03:55 +000014CodeType = type(_f.__code__)
Victor Stinner0db176f2012-04-16 00:16:30 +020015MappingProxyType = type(type.__dict__)
Barry Warsaw409da152012-06-03 16:18:47 -040016SimpleNamespace = type(sys.implementation)
Guido van Rossum85d89451994-06-23 11:53:27 +000017
Tim Peters264c6592004-07-18 00:08:11 +000018def _g():
Tim Peters3e7b1a02001-06-25 19:46:25 +000019 yield 1
Tim Peters264c6592004-07-18 00:08:11 +000020GeneratorType = type(_g())
Tim Peters3e7b1a02001-06-25 19:46:25 +000021
Guido van Rossumadc940e1994-09-29 10:04:43 +000022class _C:
Guido van Rossum898c9151997-09-04 22:12:34 +000023 def _m(self): pass
Guido van Rossum65810fe2006-05-26 19:12:38 +000024MethodType = type(_C()._m)
Guido van Rossum85d89451994-06-23 11:53:27 +000025
Guido van Rossumadc940e1994-09-29 10:04:43 +000026BuiltinFunctionType = type(len)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000027BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
Guido van Rossum85d89451994-06-23 11:53:27 +000028
29ModuleType = type(sys)
Guido van Rossum85d89451994-06-23 11:53:27 +000030
31try:
Guido van Rossum898c9151997-09-04 22:12:34 +000032 raise TypeError
Guido van Rossum85d89451994-06-23 11:53:27 +000033except TypeError:
Guido van Rossuma8add0e2007-05-14 22:03:55 +000034 tb = sys.exc_info()[2]
35 TracebackType = type(tb)
36 FrameType = type(tb.tb_frame)
Guido van Rossumf15d1591997-09-29 23:22:12 +000037 tb = None; del tb
Guido van Rossum85d89451994-06-23 11:53:27 +000038
Christian Heimes5e696852008-04-09 08:37:03 +000039# For Jython, the following two types are identical
40GetSetDescriptorType = type(FunctionType.__code__)
41MemberDescriptorType = type(FunctionType.__globals__)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000042
43del sys, _f, _g, _C, # Not for export
Nick Coghlan7fc570a2012-05-20 02:34:13 +100044
45
46# Provide a PEP 3115 compliant mechanism for class creation
47def new_class(name, bases=(), kwds=None, exec_body=None):
48 """Create a class object dynamically using the appropriate metaclass."""
49 meta, ns, kwds = prepare_class(name, bases, kwds)
50 if exec_body is not None:
51 exec_body(ns)
52 return meta(name, bases, ns, **kwds)
53
54def prepare_class(name, bases=(), kwds=None):
55 """Call the __prepare__ method of the appropriate metaclass.
56
57 Returns (metaclass, namespace, kwds) as a 3-tuple
58
59 *metaclass* is the appropriate metaclass
60 *namespace* is the prepared class namespace
61 *kwds* is an updated copy of the passed in kwds argument with any
62 'metaclass' entry removed. If no kwds argument is passed in, this will
63 be an empty dict.
64 """
65 if kwds is None:
66 kwds = {}
67 else:
68 kwds = dict(kwds) # Don't alter the provided mapping
69 if 'metaclass' in kwds:
70 meta = kwds.pop('metaclass')
71 else:
72 if bases:
73 meta = type(bases[0])
74 else:
75 meta = type
76 if isinstance(meta, type):
77 # when meta is a type, we first determine the most-derived metaclass
78 # instead of invoking the initial candidate directly
79 meta = _calculate_meta(meta, bases)
80 if hasattr(meta, '__prepare__'):
81 ns = meta.__prepare__(name, bases, **kwds)
82 else:
83 ns = {}
84 return meta, ns, kwds
85
86def _calculate_meta(meta, bases):
87 """Calculate the most derived metaclass."""
88 winner = meta
89 for base in bases:
90 base_meta = type(base)
91 if issubclass(winner, base_meta):
92 continue
93 if issubclass(base_meta, winner):
94 winner = base_meta
95 continue
96 # else:
97 raise TypeError("metaclass conflict: "
98 "the metaclass of a derived class "
99 "must be a (non-strict) subclass "
100 "of the metaclasses of all its bases")
101 return winner
Ethan Furmane03ea372013-09-25 07:14:41 -0700102
103class DynamicClassAttribute:
104 """Route attribute access on a class to __getattr__.
105
106 This is a descriptor, used to define attributes that act differently when
107 accessed through an instance and through a class. Instance access remains
108 normal, but access to an attribute through a class will be routed to the
109 class's __getattr__ method; this is done by raising AttributeError.
110
111 This allows one to have properties active on an instance, and have virtual
112 attributes on the class with the same name (see Enum for an example).
113
114 """
115 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
116 self.fget = fget
117 self.fset = fset
118 self.fdel = fdel
119 # next two lines make DynamicClassAttribute act the same as property
120 self.__doc__ = doc or fget.__doc__ or self.__doc__
121 self.overwrite_doc = doc is None
122 # support for abstract methods
123 self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False))
124
125 def __get__(self, instance, ownerclass=None):
126 if instance is None:
127 if self.__isabstractmethod__:
128 return self
129 raise AttributeError()
130 elif self.fget is None:
131 raise AttributeError("unreadable attribute")
132 return self.fget(instance)
133
134 def __set__(self, instance, value):
135 if self.fset is None:
136 raise AttributeError("can't set attribute")
137 self.fset(instance, value)
138
139 def __delete__(self, instance):
140 if self.fdel is None:
141 raise AttributeError("can't delete attribute")
142 self.fdel(instance)
143
144 def getter(self, fget):
145 fdoc = fget.__doc__ if self.overwrite_doc else None
146 result = type(self)(fget, self.fset, self.fdel, fdoc or self.__doc__)
147 result.overwrite_doc = self.overwrite_doc
148 return result
149
150 def setter(self, fset):
151 result = type(self)(self.fget, fset, self.fdel, self.__doc__)
152 result.overwrite_doc = self.overwrite_doc
153 return result
154
155 def deleter(self, fdel):
156 result = type(self)(self.fget, self.fset, fdel, self.__doc__)
157 result.overwrite_doc = self.overwrite_doc
158 return result