# HG changeset patch # User Stephen Thorne # Parent d9c98730e2e87b09096bc98e535e5683cb969ea4 Issue #14905: zipimport.c now does not require directory entries to exist in the zipfile manifest in order to import modules within namespaces. diff -r d9c98730e2e8 Lib/test/test_namespace_pkgs.py --- a/Lib/test/test_namespace_pkgs.py Sat Jul 07 13:34:50 2012 +1000 +++ b/Lib/test/test_namespace_pkgs.py Sat Jul 07 16:45:39 2012 +0200 @@ -254,9 +254,8 @@ class ZipWithMissingDirectory(NamespacePackageTest): paths = ['missing_directory.zip'] - @unittest.expectedFailure def test_missing_directory(self): - # This will fail because missing_directory.zip contains: + # missing_directory.zip contains: # Length Date Time Name # --------- ---------- ----- ---- # 29 2012-05-03 18:13 foo/one.py @@ -265,8 +264,8 @@ # --------- ------- # 67 3 files - # Because there is no 'foo/', the zipimporter currently doesn't - # know that foo is a namespace package + # foo/ should be synthesised and added to zipimporter's internal state, + # allowing import foo.one to work. import foo.one diff -r d9c98730e2e8 Misc/NEWS --- a/Misc/NEWS Sat Jul 07 13:34:50 2012 +1000 +++ b/Misc/NEWS Sat Jul 07 16:45:39 2012 +0200 @@ -54,6 +54,9 @@ - Issue #15194: Update libffi to the 3.0.11 release. +- Issue #14905: zipimport.c now does not require directory entries to exist in + the zipfile manifest in order to import modules within namespaces. + Tools/Demos ----------- diff -r d9c98730e2e8 Modules/zipimport.c --- a/Modules/zipimport.c Sat Jul 07 13:34:50 2012 +1000 +++ b/Modules/zipimport.c Sat Jul 07 16:45:39 2012 +0200 @@ -859,6 +859,7 @@ Py_ssize_t i; char name[MAXPATHLEN + 5]; PyObject *nameobj = NULL; + PyObject *dirnameobj = NULL; char *p, endof_central_dir[22]; Py_ssize_t arc_offset; /* Absolute offset to start of the zip-archive. */ PyObject *path; @@ -965,10 +966,40 @@ if (t == NULL) goto error; err = PyDict_SetItem(files, nameobj, t); - Py_CLEAR(nameobj); Py_DECREF(t); if (err != 0) goto error; + + Py_UCS4 c; + for (i = 0; i < PyUnicode_GetLength(nameobj) - 1; i++) { + c = PyUnicode_READ_CHAR(nameobj, i); + if (c != SEP) + continue; + + dirnameobj = PyUnicode_Substring(nameobj, 0, i+1); + if (dirnameobj == NULL) + goto error; + if (PyDict_Contains(files, dirnameobj)) { + Py_CLEAR(dirnameobj); + continue; + } + + path = PyUnicode_FromFormat("%U%c%U", archive, SEP, dirnameobj); + if (path == NULL) + goto error; + + t = Py_BuildValue("Nhllnhhl", path, 0, 0, 0, 0, 0, 0, 0); + if (t == NULL) + goto error; + err = PyDict_SetItem(files, dirnameobj, t); + Py_CLEAR(dirnameobj); + Py_DECREF(t); + if (err != 0) { + goto error; + } + count++; + } + Py_CLEAR(nameobj); count++; } fclose(fp); @@ -980,6 +1011,7 @@ fclose(fp); Py_XDECREF(files); Py_XDECREF(nameobj); + Py_XDECREF(dirnameobj); return NULL; }