functions: revert the function init order to make pylint happy again. See #217
[pygobject.git] / gi / types.py
blob47ed18a5aa4d3bd40143c60d597fdc32e0b92741
1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
4 # Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
6 # types.py: base types for introspected items.
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 # USA
23 from __future__ import absolute_import
25 import warnings
26 import re
28 from ._constants import TYPE_INVALID
29 from .docstring import generate_doc_string
31 from ._gi import \
32 InterfaceInfo, \
33 ObjectInfo, \
34 StructInfo, \
35 VFuncInfo, \
36 register_interface_info, \
37 hook_up_vfunc_implementation, \
38 GInterface
39 from . import _gi
41 StructInfo, GInterface # pyflakes
43 from . import _propertyhelper as propertyhelper
44 from . import _signalhelper as signalhelper
47 def snake_case(name):
48 s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
49 return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
52 class MetaClassHelper(object):
53 def _setup_methods(cls):
54 for method_info in cls.__info__.get_methods():
55 setattr(cls, method_info.__name__, method_info)
57 def _setup_class_methods(cls):
58 info = cls.__info__
59 class_struct = info.get_class_struct()
60 if class_struct is None:
61 return
62 for method_info in class_struct.get_methods():
63 name = method_info.__name__
64 # Don't mask regular methods or base class methods with TypeClass methods.
65 if not hasattr(cls, name):
66 setattr(cls, name, classmethod(method_info))
68 def _setup_fields(cls):
69 for field_info in cls.__info__.get_fields():
70 name = field_info.get_name().replace('-', '_')
71 setattr(cls, name, property(field_info.get_value, field_info.set_value))
73 def _setup_constants(cls):
74 for constant_info in cls.__info__.get_constants():
75 name = constant_info.get_name()
76 value = constant_info.get_value()
77 setattr(cls, name, value)
79 def _setup_vfuncs(cls):
80 for vfunc_name, py_vfunc in cls.__dict__.items():
81 if not vfunc_name.startswith("do_") or not callable(py_vfunc):
82 continue
84 skip_ambiguity_check = False
86 # If a method name starts with "do_" assume it is a vfunc, and search
87 # in the base classes for a method with the same name to override.
88 # Recursion is necessary as overriden methods in most immediate parent
89 # classes may shadow vfuncs from classes higher in the hierarchy.
90 vfunc_info = None
91 for base in cls.__mro__:
92 method = getattr(base, vfunc_name, None)
93 if method is not None and isinstance(method, VFuncInfo):
94 vfunc_info = method
95 break
97 if not hasattr(base, '__info__') or not hasattr(base.__info__, 'get_vfuncs'):
98 continue
100 base_name = snake_case(base.__info__.get_type_name())
102 for v in base.__info__.get_vfuncs():
103 if vfunc_name == 'do_%s_%s' % (base_name, v.get_name()):
104 vfunc_info = v
105 skip_ambiguity_check = True
106 break
108 if vfunc_info:
109 break
111 # If we did not find a matching method name in the bases, we might
112 # be overriding an interface virtual method. Since interfaces do not
113 # provide implementations, there will be no method attribute installed
114 # on the object. Instead we have to search through
115 # InterfaceInfo.get_vfuncs(). Note that the infos returned by
116 # get_vfuncs() use the C vfunc name (ie. there is no "do_" prefix).
117 if vfunc_info is None:
118 vfunc_info = find_vfunc_info_in_interface(cls.__bases__, vfunc_name[len("do_"):])
120 if vfunc_info is not None:
121 # Check to see if there are vfuncs with the same name in the bases.
122 # We have no way of specifying which one we are supposed to override.
123 if not skip_ambiguity_check:
124 ambiguous_base = find_vfunc_conflict_in_bases(vfunc_info, cls.__bases__)
125 if ambiguous_base is not None:
126 base_info = vfunc_info.get_container()
127 raise TypeError('Method %s() on class %s.%s is ambiguous '
128 'with methods in base classes %s.%s and %s.%s' %
129 (vfunc_name,
130 cls.__info__.get_namespace(),
131 cls.__info__.get_name(),
132 base_info.get_namespace(),
133 base_info.get_name(),
134 ambiguous_base.__info__.get_namespace(),
135 ambiguous_base.__info__.get_name()
137 hook_up_vfunc_implementation(vfunc_info, cls.__gtype__,
138 py_vfunc)
140 def _setup_native_vfuncs(cls):
141 # Only InterfaceInfo and ObjectInfo have the get_vfuncs() method.
142 # We skip InterfaceInfo because interfaces have no implementations for vfuncs.
143 # Also check if __info__ in __dict__, not hasattr('__info__', ...)
144 # because we do not want to accidentally retrieve __info__ from a base class.
145 class_info = cls.__dict__.get('__info__')
146 if class_info is None or not isinstance(class_info, ObjectInfo):
147 return
149 # Special case skipping of vfuncs for GObject.Object because they will break
150 # the static bindings which will try to use them.
151 if cls.__module__ == 'gi.repository.GObject' and cls.__name__ == 'Object':
152 return
154 for vfunc_info in class_info.get_vfuncs():
155 name = 'do_%s' % vfunc_info.__name__
156 setattr(cls, name, vfunc_info)
159 def find_vfunc_info_in_interface(bases, vfunc_name):
160 for base in bases:
161 # All wrapped interfaces inherit from GInterface.
162 # This can be seen in IntrospectionModule.__getattr__() in module.py.
163 # We do not need to search regular classes here, only wrapped interfaces.
164 # We also skip GInterface, because it is not wrapped and has no __info__ attr.
165 # Skip bases without __info__ (static _gi.GObject)
166 if base is GInterface or\
167 not issubclass(base, GInterface) or\
168 not hasattr(base, '__info__'):
169 continue
171 # Only look at this classes vfuncs if it is an interface.
172 if isinstance(base.__info__, InterfaceInfo):
173 for vfunc in base.__info__.get_vfuncs():
174 if vfunc.get_name() == vfunc_name:
175 return vfunc
177 # Recurse into the parent classes
178 vfunc = find_vfunc_info_in_interface(base.__bases__, vfunc_name)
179 if vfunc is not None:
180 return vfunc
182 return None
185 def find_vfunc_conflict_in_bases(vfunc, bases):
186 for klass in bases:
187 if not hasattr(klass, '__info__') or \
188 not hasattr(klass.__info__, 'get_vfuncs'):
189 continue
190 vfuncs = klass.__info__.get_vfuncs()
191 vfunc_name = vfunc.get_name()
192 for v in vfuncs:
193 if v.get_name() == vfunc_name and v != vfunc:
194 return klass
196 aklass = find_vfunc_conflict_in_bases(vfunc, klass.__bases__)
197 if aklass is not None:
198 return aklass
199 return None
202 class _GObjectMetaBase(type):
203 """Metaclass for automatically registering GObject classes."""
204 def __init__(cls, name, bases, dict_):
205 type.__init__(cls, name, bases, dict_)
206 propertyhelper.install_properties(cls)
207 signalhelper.install_signals(cls)
208 cls._type_register(cls.__dict__)
210 def _type_register(cls, namespace):
211 # don't register the class if already registered
212 if '__gtype__' in namespace:
213 return
215 # Do not register a new GType for the overrides, as this would sort of
216 # defeat the purpose of overrides...
217 if cls.__module__.startswith('gi.overrides.'):
218 return
220 _gi.type_register(cls, namespace.get('__gtype_name__'))
223 _gi._install_metaclass(_GObjectMetaBase)
226 class GObjectMeta(_GObjectMetaBase, MetaClassHelper):
227 """Meta class used for GI GObject based types."""
228 def __init__(cls, name, bases, dict_):
229 super(GObjectMeta, cls).__init__(name, bases, dict_)
230 is_gi_defined = False
231 if cls.__module__ == 'gi.repository.' + cls.__info__.get_namespace():
232 is_gi_defined = True
234 is_python_defined = False
235 if not is_gi_defined and cls.__module__ != GObjectMeta.__module__:
236 is_python_defined = True
238 if is_python_defined:
239 cls._setup_vfuncs()
240 elif is_gi_defined:
241 if isinstance(cls.__info__, ObjectInfo):
242 cls._setup_class_methods()
243 cls._setup_methods()
244 cls._setup_constants()
245 cls._setup_native_vfuncs()
247 if isinstance(cls.__info__, ObjectInfo):
248 cls._setup_fields()
249 elif isinstance(cls.__info__, InterfaceInfo):
250 register_interface_info(cls.__info__.get_g_type())
252 def mro(cls):
253 return mro(cls)
255 @property
256 def __doc__(cls):
257 """Meta class property which shows up on any class using this meta-class."""
258 if cls == GObjectMeta:
259 return ''
261 doc = cls.__dict__.get('__doc__', None)
262 if doc is not None:
263 return doc
265 # For repository classes, dynamically generate a doc string if it wasn't overridden.
266 if cls.__module__.startswith(('gi.repository.', 'gi.overrides')):
267 return generate_doc_string(cls.__info__)
269 return None
272 def mro(C):
273 """Compute the class precedence list (mro) according to C3, with GObject
274 interface considerations.
276 We override Python's MRO calculation to account for the fact that
277 GObject classes are not affected by the diamond problem:
278 http://en.wikipedia.org/wiki/Diamond_problem
280 Based on http://www.python.org/download/releases/2.3/mro/
282 # TODO: If this turns out being too slow, consider using generators
283 bases = []
284 bases_of_subclasses = [[C]]
286 if C.__bases__:
287 for base in C.__bases__:
288 # Python causes MRO's to be calculated starting with the lowest
289 # base class and working towards the descendant, storing the result
290 # in __mro__ at each point. Therefore at this point we know that
291 # we already have our base class MRO's available to us, there is
292 # no need for us to (re)calculate them.
293 if hasattr(base, '__mro__'):
294 bases_of_subclasses += [list(base.__mro__)]
295 else:
296 warnings.warn('Mixin class %s is an old style class, please '
297 'update this to derive from "object".' % base,
298 RuntimeWarning)
299 # For old-style classes (Python2 only), the MRO is not
300 # easily accessible. As we do need it here, we calculate
301 # it via recursion, according to the C3 algorithm. Using C3
302 # for old style classes deviates from Python's own behaviour,
303 # but visible effects here would be a corner case triggered by
304 # questionable design.
305 bases_of_subclasses += [mro(base)]
306 bases_of_subclasses += [list(C.__bases__)]
308 while bases_of_subclasses:
309 for subclass_bases in bases_of_subclasses:
310 candidate = subclass_bases[0]
311 not_head = [s for s in bases_of_subclasses if candidate in s[1:]]
312 if not_head and GInterface not in candidate.__bases__:
313 candidate = None # conflict, reject candidate
314 else:
315 break
317 if candidate is None:
318 raise TypeError('Cannot create a consistent method resolution '
319 'order (MRO)')
321 bases.append(candidate)
323 for subclass_bases in bases_of_subclasses[:]: # remove candidate
324 if subclass_bases and subclass_bases[0] == candidate:
325 del subclass_bases[0]
326 if not subclass_bases:
327 bases_of_subclasses.remove(subclass_bases)
329 return bases
332 def nothing(*args, **kwargs):
333 pass
336 class StructMeta(type, MetaClassHelper):
337 """Meta class used for GI Struct based types."""
339 def __init__(cls, name, bases, dict_):
340 super(StructMeta, cls).__init__(name, bases, dict_)
342 # Avoid touching anything else than the base class.
343 g_type = cls.__info__.get_g_type()
344 if g_type != TYPE_INVALID and g_type.pytype is not None:
345 return
347 cls._setup_fields()
348 cls._setup_methods()
350 for method_info in cls.__info__.get_methods():
351 if method_info.is_constructor() and \
352 method_info.__name__ == 'new' and \
353 (not method_info.get_arguments() or
354 cls.__info__.get_size() == 0):
355 cls.__new__ = staticmethod(method_info)
356 # Boxed will raise an exception
357 # if arguments are given to __init__
358 cls.__init__ = nothing
359 break
361 @property
362 def __doc__(cls):
363 if cls == StructMeta:
364 return ''
365 return generate_doc_string(cls.__info__)