[IronPython] infinite import loop for nested packages (and fix)

Andrew Sutherland sombrero at gmail.com
Thu Mar 2 08:14:22 CET 2006


If you have a directory on your python path like so:

foo/
  __init__.py: import foo.bar as bar
  bar/
    __init__.py: import foo.bar.baz as baz
    baz.py: print 'Baz imported'
testit.py: import foo.bar

And you run testit.py, the import process will go into an infinite
loop while importing 'foo.bar' because an effort is only made to see
if the top-level package already exists.  Although it will find 'foo'
alright in that fashion, it will repeatedly look up 'foo.bar' because
the name traversal logic in Importer::ImportModule finds 'foo' already
exists, then goes to import foo.bar again.

A solution that works follows.

        internal static object ImportModule(PythonModule mod, string
fullName, bool bottom) {
            string[] names = fullName.Split('.');
            object newmod = null;

            // Find the most specific already-existing module if we may.
            // Since the module import mechanism in CPython is not backtracking,
            //  this is a safe behaviour.
            string nameRemaining = fullName;

            // (At the conclusion of this loop,) the index of the name
thus looked up.  In the
            //  event our loop fails, iNameSatisfied will be zero.
            int iNameSatisfied = names.Length - 1;
            while(nameRemaining.LastIndexOf('.') >= 0) {
                if(TryGetExistingModule(nameRemaining, out newmod)) {
                    break;
                }
                else {
                    nameRemaining = nameRemaining.Substring(0,
nameRemaining.LastIndexOf('.'));
                    iNameSatisfied--;
                }
            }

            if(iNameSatisfied == 0)
            {
                newmod = ImportTopFrom(mod, names[0]);
            }
            else if (names.Length == 1)
            {
                // if we imported before having the assembly
                // loaded and then loaded the assembly we want
                // to make the assembly available now.

                PythonModule pm = newmod as PythonModule;
                if (pm.InnerModule != null) pm.PackageImported = true;
            }

            if (newmod == null) {
                newmod = ImportTop(mod, names[0]);
                if (newmod == null) return null;
            }

            object next = newmod;
            for (int i = iNameSatisfied + 1; i < names.Length; i++) {
                next = ImportFrom(next, names[i]);
            }

            return bottom ? next : newmod;
        }

Andrew



More information about the Ironpython-users mailing list