Basic Python 3.3 compatibility #109

Closed
wants to merge 1 commit into
from

Projects

None yet

3 participants

@1st1
1st1 commented Jan 10, 2013

In python 3.3 the implementation of the import system is rewritten from scratch and based on importlib. Also some new functionality was introduced, such as namespace packages (directories in pythonpath without init.py files)

This fix restores most of failing unittests under 3.3, and adds basic support for namespace packages.

This commit is very WIP, and maybe considered as a proof of concept.

@davidhalter davidhalter commented on the diff Jan 11, 2013
jedi/imports.py
@@ -249,7 +257,24 @@ def follow_str(ns_path, string):
for i, s in enumerate(self.import_path):
try:
current_namespace = follow_str(current_namespace[1], s)
- except ImportError:
+ if not current_namespace[1] and is_py33:
+ loader = importlib.find_loader(s)
@davidhalter
davidhalter Jan 11, 2013 Owner

Are you sure this is ever used? Because follow_str tends to or fail with an ImportError. But since I'm not really getting the Python 3.3 imports, could you explain what this part does?

@1st1
1st1 Jan 11, 2013

Yes, it's used under 3.3 when you're inspecting an import of a namespace package. In this case, imp.find_module simply fails with ImportError, however import_lib.find_loader returns _frozen_importlib.NamespaceLoader object.

@1st1
1st1 Jan 11, 2013

Ideally, imports.py needs to be rewritten just for 3.3 (with the use of importlib only), but that's too much of a time investment right now.

@davidhalter
davidhalter Jan 11, 2013 Owner

Hmm why don't we use a completely different mechanism for >= py3.3? I think this is not too complicated, because we would just need to rewrite the parts of _follow_file_system until f = None. -> 80 lines.

I have no idea how good importlib is... But it really sounds like we should switch away from imp.

@davidhalter davidhalter commented on the diff Jan 11, 2013
jedi/imports.py
@@ -249,7 +257,24 @@ def follow_str(ns_path, string):
for i, s in enumerate(self.import_path):
try:
current_namespace = follow_str(current_namespace[1], s)
- except ImportError:
+ if not current_namespace[1] and is_py33:
+ loader = importlib.find_loader(s)
+ if loader.__name__ == 'BuiltinImporter':
+ current_namespace = (current_namespace[0], s,
+ current_namespace[2])
+
+ except ImportError as ex:
@davidhalter
davidhalter Jan 11, 2013 Owner

Could you remove the as ex? Python 2.5 compatibility.

@1st1 1st1 commented on the diff Jan 11, 2013
jedi/imports.py
@@ -249,7 +257,24 @@ def follow_str(ns_path, string):
for i, s in enumerate(self.import_path):
try:
current_namespace = follow_str(current_namespace[1], s)
- except ImportError:
+ if not current_namespace[1] and is_py33:
+ loader = importlib.find_loader(s)
+ if loader.__name__ == 'BuiltinImporter':
@1st1
1st1 Jan 11, 2013

I don't like this line, I'll take a look if it's possible to change it to isinstance check.

@1st1 1st1 commented on the diff Jan 11, 2013
jedi/imports.py
@@ -249,7 +257,24 @@ def follow_str(ns_path, string):
for i, s in enumerate(self.import_path):
try:
current_namespace = follow_str(current_namespace[1], s)
- except ImportError:
+ if not current_namespace[1] and is_py33:
+ loader = importlib.find_loader(s)
+ if loader.__name__ == 'BuiltinImporter':
+ current_namespace = (current_namespace[0], s,
+ current_namespace[2])
+
+ except ImportError as ex:
+ if not i and is_py33:
+ loader = importlib.find_loader(s)
+ if 'NamespaceLoader' in repr(loader):
@1st1
1st1 Jan 11, 2013

'NamespaceLoader' in repr(loader) is also ugly as hell. The problem is that parts of importlib is compiled in a frozen module, and those classes are separated from what we have defined in importlib._bootstrap. Anyways, I'll take a look at this again today.

@schlamar

This could be closed now, too :)

@davidhalter
Owner

Closing, because this has been solved by #187.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment