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
23 from __future__
import absolute_import
28 from ._constants
import TYPE_INVALID
29 from .docstring
import generate_doc_string
36 register_interface_info
, \
37 hook_up_vfunc_implementation
, \
41 StructInfo
, GInterface
# pyflakes
43 from . import _propertyhelper
as propertyhelper
44 from . import _signalhelper
as signalhelper
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
):
59 class_struct
= info
.get_class_struct()
60 if class_struct
is None:
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
):
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.
91 for base
in cls
.__mro
__:
92 method
= getattr(base
, vfunc_name
, None)
93 if method
is not None and isinstance(method
, VFuncInfo
):
97 if not hasattr(base
, '__info__') or not hasattr(base
.__info
__, 'get_vfuncs'):
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()):
105 skip_ambiguity_check
= True
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' %
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
__,
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
):
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':
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
):
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__'):
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
:
177 # Recurse into the parent classes
178 vfunc
= find_vfunc_info_in_interface(base
.__bases
__, vfunc_name
)
179 if vfunc
is not None:
185 def find_vfunc_conflict_in_bases(vfunc
, bases
):
187 if not hasattr(klass
, '__info__') or \
188 not hasattr(klass
.__info
__, 'get_vfuncs'):
190 vfuncs
= klass
.__info
__.get_vfuncs()
191 vfunc_name
= vfunc
.get_name()
193 if v
.get_name() == vfunc_name
and v
!= vfunc
:
196 aklass
= find_vfunc_conflict_in_bases(vfunc
, klass
.__bases
__)
197 if aklass
is not 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
:
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.'):
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():
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
:
241 if isinstance(cls
.__info
__, ObjectInfo
):
242 cls
._setup
_class
_methods
()
244 cls
._setup
_constants
()
245 cls
._setup
_native
_vfuncs
()
247 if isinstance(cls
.__info
__, ObjectInfo
):
249 elif isinstance(cls
.__info
__, InterfaceInfo
):
250 register_interface_info(cls
.__info
__.get_g_type())
257 """Meta class property which shows up on any class using this meta-class."""
258 if cls
== GObjectMeta
:
261 doc
= cls
.__dict
__.get('__doc__', None)
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
__)
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
284 bases_of_subclasses
= [[C
]]
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
__)]
296 warnings
.warn('Mixin class %s is an old style class, please '
297 'update this to derive from "object".' % base
,
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
317 if candidate
is None:
318 raise TypeError('Cannot create a consistent method resolution '
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
)
332 def nothing(*args
, **kwargs
):
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:
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
363 if cls
== StructMeta
:
365 return generate_doc_string(cls
.__info
__)