OLD | NEW |
1 """Astroid hooks for the Python 2 GObject introspection bindings. | 1 """Astroid hooks for the Python 2 GObject introspection bindings. |
2 | 2 |
3 Helps with understanding everything imported from 'gi.repository' | 3 Helps with understanding everything imported from 'gi.repository' |
4 """ | 4 """ |
5 | 5 |
6 import inspect | 6 import inspect |
| 7 import itertools |
7 import sys | 8 import sys |
8 import re | 9 import re |
9 | 10 |
10 from astroid import MANAGER, AstroidBuildingException | 11 from astroid import MANAGER, AstroidBuildingException |
11 from astroid.builder import AstroidBuilder | 12 from astroid.builder import AstroidBuilder |
12 | 13 |
13 | 14 |
14 _inspected_modules = {} | 15 _inspected_modules = {} |
15 | 16 |
16 _identifier_re = r'^[A-Za-z_]\w*$' | 17 _identifier_re = r'^[A-Za-z_]\w*$' |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 classret = _gi_build_stub(classes[name]) | 105 classret = _gi_build_stub(classes[name]) |
105 if not classret: | 106 if not classret: |
106 classret = "pass\n" | 107 classret = "pass\n" |
107 | 108 |
108 for line in classret.splitlines(): | 109 for line in classret.splitlines(): |
109 ret += " " + line + "\n" | 110 ret += " " + line + "\n" |
110 ret += "\n" | 111 ret += "\n" |
111 | 112 |
112 return ret | 113 return ret |
113 | 114 |
114 # Overwrite Module.module_import to _actually_ import the introspected module if | 115 def _import_gi_module(modname): |
115 # it's a gi module, then build stub code by examining its info and get an astng | 116 # we only consider gi.repository submodules |
116 # from that | 117 if not modname.startswith('gi.repository.'): |
117 | 118 raise AstroidBuildingException() |
118 from astroid.scoped_nodes import Module | |
119 _orig_import_module = Module.import_module | |
120 | |
121 def _new_import_module(self, modname, relative_only=False, level=None): | |
122 # Could be a static piece of gi.repository or whatever unrelated module, | |
123 # let that fall through | |
124 try: | |
125 return _orig_import_module(self, modname, relative_only, level) | |
126 except AstroidBuildingException: | |
127 # we only consider gi.repository submodules | |
128 if not modname.startswith('gi.repository.'): | |
129 if relative_only and level is None: | |
130 level = 0 | |
131 modname = self.relative_to_absolute_name(modname, level) | |
132 if not modname.startswith('gi.repository.'): | |
133 raise | |
134 # build astroid representation unless we already tried so | 119 # build astroid representation unless we already tried so |
135 if modname not in _inspected_modules: | 120 if modname not in _inspected_modules: |
136 modnames = [modname] | 121 modnames = [modname] |
137 # GLib and GObject have some special case handling | 122 optional_modnames = [] |
138 # in pygobject that we need to cope with | 123 |
| 124 # GLib and GObject may have some special case handling |
| 125 # in pygobject that we need to cope with. However at |
| 126 # least as of pygobject3-3.13.91 the _glib module doesn't |
| 127 # exist anymore, so if treat these modules as optional. |
139 if modname == 'gi.repository.GLib': | 128 if modname == 'gi.repository.GLib': |
140 modnames.append('gi._glib') | 129 optional_modnames.append('gi._glib') |
141 elif modname == 'gi.repository.GObject': | 130 elif modname == 'gi.repository.GObject': |
142 modnames.append('gi._gobject') | 131 optional_modnames.append('gi._gobject') |
| 132 |
143 try: | 133 try: |
144 modcode = '' | 134 modcode = '' |
145 for m in modnames: | 135 for m in itertools.chain(modnames, optional_modnames): |
146 __import__(m) | 136 try: |
147 modcode += _gi_build_stub(sys.modules[m]) | 137 __import__(m) |
| 138 modcode += _gi_build_stub(sys.modules[m]) |
| 139 except ImportError: |
| 140 if m not in optional_modnames: |
| 141 raise |
148 except ImportError: | 142 except ImportError: |
149 astng = _inspected_modules[modname] = None | 143 astng = _inspected_modules[modname] = None |
150 else: | 144 else: |
151 astng = AstroidBuilder(MANAGER).string_build(modcode, modname) | 145 astng = AstroidBuilder(MANAGER).string_build(modcode, modname) |
152 _inspected_modules[modname] = astng | 146 _inspected_modules[modname] = astng |
153 else: | 147 else: |
154 astng = _inspected_modules[modname] | 148 astng = _inspected_modules[modname] |
155 if astng is None: | 149 if astng is None: |
156 raise AstroidBuildingException('Failed to import module %r' % modname) | 150 raise AstroidBuildingException('Failed to import module %r' % modname) |
157 return astng | 151 return astng |
158 | 152 |
159 Module.import_module = _new_import_module | 153 |
| 154 MANAGER.register_failed_import_hook(_import_gi_module) |
| 155 |
OLD | NEW |