Added support for relative import (new in Python2.5)

git-svn-id: http://svn.pyinstaller.org/trunk@526 8dd32b29-ccff-0310-8a9a-9233e24343b1
This commit is contained in:
htgoebel
2008-08-05 17:31:49 +00:00
parent 3ba5b9f3a5
commit 9a77008f6c
2 changed files with 90 additions and 32 deletions
+30 -11
View File
@@ -342,11 +342,33 @@ class ImportManager:
# first see if we could be importing a relative name
#print "importHook(%s, %s, locals, %s)" % (name, getattr(globals, '__name__', None), fromlist)
_sys_modules_get = sys.modules.get
contexts = [None]
if globals and level == -1:
# The level indicates we should attempt relative imports, add the
# package to searched contexts
_self_doimport = self.doimport
threaded = self.threaded
# break the name being imported up so we get:
# a.b.c -> [a, b, c]
nmparts = namesplit(name)
if not globals:
contexts = [None]
if level >= 0:
raise ImportError("Relative import requires 'globals'")
elif level == 0:
# absolute import, do not try relative
contexts = [None]
else: # level != 0
importernm = globals.get('__name__', '')
if level < 0:
# behaviour up to Python 2.4 (and default in Python 2.5)
# add the package to searched contexts
contexts = [None]
else:
# relative import, do not try absolute
if not importernm:
raise ImportError("Relative import requires package")
importernm = _string_split(importernm, '.')[:-level]
importernm = _string_join('.', importernm)
contexts = []
if importernm:
if hasattr(_sys_modules_get(importernm), '__path__'):
# If you use the "from __init__ import" syntax, the package
@@ -357,15 +379,12 @@ class ImportManager:
else:
pkgnm = packagename(importernm)
if pkgnm:
contexts.insert(0,pkgnm)
# so contexts is [pkgnm, None] or just [None]
# now break the name being imported up so we get:
# a.b.c -> [a, b, c]
nmparts = namesplit(name)
_self_doimport = self.doimport
threaded = self.threaded
contexts.insert(0, pkgnm)
# so contexts is [pkgnm, None], [pkgnm] or just [None]
for context in contexts:
ctx = context
i = 0
for i in range(len(nmparts)):
nm = nmparts[i]
#print " importHook trying %s in %s" % (nm, ctx)
+60 -21
View File
@@ -399,29 +399,48 @@ class ImportTracker:
mod = self.modules[nm]
if mod:
mod.xref(importer)
for name, isdelayed, isconditional in mod.imports:
for name, isdelayed, isconditional, level in mod.imports:
imptyp = isdelayed * 2 + isconditional
newnms = self.analyze_one(name, nm, imptyp)
newnms = self.analyze_one(name, nm, imptyp, level)
newnms = map(None, newnms, [nm]*len(newnms))
nms[j:j] = newnms
j = j + len(newnms)
return map(lambda a: a[0], nms)
def analyze_one(self, nm, importernm=None, imptyp=0):
# first see if we could be importing a relative name
contexts = [None]
_all = None
if importernm:
if self.ispackage(importernm):
contexts.insert(0,importernm)
else:
pkgnm = string.join(string.split(importernm, '.')[:-1], '.')
if pkgnm:
contexts.insert(0,pkgnm)
# so contexts is [pkgnm, None] or just [None]
# now break the name being imported up so we get:
# a.b.c -> [a, b, c]
def analyze_one(self, nm, importernm=None, imptyp=0, level=-1):
#print '## analyze_one', nm, importernm, imptyp, level
# break the name being imported up so we get:
# a.b.c -> [a, b, c] ; ..z -> ['', '', z]
if not nm:
nm = importernm
importernm = None
level = 0
nmparts = string.split(nm, '.')
if level < 0:
# behaviour up to Python 2.4 (and default in Python 2.5)
# first see if we could be importing a relative name
contexts = [None]
if importernm:
if self.ispackage(importernm):
contexts.insert(0, importernm)
else:
pkgnm = string.join(string.split(importernm, '.')[:-1], '.')
if pkgnm:
contexts.insert(0, pkgnm)
elif level == 0:
# absolute import, do not try relative
importernm = None
contexts = [None]
elif level > 0:
# relative import, do not try absolute
contexts = [string.join(string.split(importernm, '.')[:-level], '.')]
importernm = None
_all = None
assert contexts
# so contexts is [pkgnm, None] or just [None]
if nmparts[-1] == '*':
del nmparts[-1]
_all = []
@@ -534,7 +553,7 @@ class ImportTracker:
mod = hook.hook(mod)
if hasattr(hook, 'hiddenimports'):
for impnm in hook.hiddenimports:
mod.imports.append((impnm, 0, 0))
mod.imports.append((impnm, 0, 0, -1))
if hasattr(hook, 'attrs'):
for attr, val in hook.attrs:
setattr(mod, attr, val)
@@ -703,6 +722,10 @@ except ValueError:
SET_LINENO = 999
BUILD_LIST = dis.opname.index('BUILD_LIST')
LOAD_CONST = dis.opname.index('LOAD_CONST')
if getattr(sys, 'version_info', (0,0,0)) > (2,5,0):
LOAD_CONST_level = LOAD_CONST
else:
LOAD_CONST_level = 999
JUMP_IF_FALSE = dis.opname.index('JUMP_IF_FALSE')
JUMP_IF_TRUE = dis.opname.index('JUMP_IF_TRUE')
JUMP_FORWARD = dis.opname.index('JUMP_FORWARD')
@@ -752,17 +775,28 @@ def scan_code(co, m=None, w=None, nested=0):
w = []
all = None
lastname = None
level = -1 # import-level, same behaviour as up to Python 2.4
for i in range(len(instrs)):
op, oparg, conditional, curline = instrs[i]
if op == IMPORT_NAME:
name = lastname = co.co_names[oparg]
m.append((name, nested, conditional))
if level <= 0:
name = lastname = co.co_names[oparg]
else:
name = lastname = co.co_names[oparg]
#print 'import_name', name, `lastname`, level
m.append((name, nested, conditional, level))
elif op == IMPORT_FROM:
name = co.co_names[oparg]
m.append((lastname+'.'+name, nested, conditional))
#print 'import_from', name, `lastname`, level,
if level > 0 and (not lastname or lastname[-1:] == '.'):
name = lastname + name
else:
name = lastname + '.' + name
#print name
m.append((name, nested, conditional, level))
assert lastname is not None
elif op == IMPORT_STAR:
m.append((lastname+'.*', nested, conditional))
m.append((lastname+'.*', nested, conditional, level))
elif op == STORE_NAME:
if co.co_names[oparg] == "__all__":
j = i - 1
@@ -780,6 +814,11 @@ def scan_code(co, m=None, w=None, nested=0):
break
elif op in STORE_OPS:
pass
elif op == LOAD_CONST_level:
# starting with Python 2.5, _each_ import is preceeded with a
# LOAD_CONST to indicate the relative level.
if isinstance(co.co_consts[oparg], (int, long)):
level = co.co_consts[oparg]
elif op == LOAD_GLOBAL:
name = co.co_names[oparg]
cndtl = ['', 'conditional'][conditional]