Discussion:
[Python-checkins] cpython (merge default -> default): merge heads
benjamin.peterson
2014-10-13 19:51:39 UTC
Permalink
https://hg.python.org/cpython/rev/6015b23bf918
changeset: 93036:6015b23bf918
parent: 93034:2b5707b6caf9
parent: 93030:4a51fb82b827
user: Benjamin Peterson <benjamin at python.org>
date: Mon Oct 13 15:50:50 2014 -0400
summary:
merge heads

files:
Lib/socketserver.py | 8 +-
Lib/test/test_import.py | 42 +++++++++-
Lib/test/test_import/__main__.py | 3 +
Lib/test/test_import/data/circular_imports/basic.py | 2 +
Lib/test/test_import/data/circular_imports/basic2.py | 1 +
Lib/test/test_import/data/circular_imports/indirect.py | 1 +
Lib/test/test_import/data/circular_imports/rebinding.py | 3 +
Lib/test/test_import/data/circular_imports/rebinding2.py | 3 +
Lib/test/test_import/data/circular_imports/subpackage.py | 2 +
Lib/test/test_import/data/circular_imports/subpkg/subpackage2.py | 2 +
Lib/test/test_import/data/circular_imports/subpkg/util.py | 2 +
Lib/test/test_import/data/circular_imports/util.py | 2 +
Lib/test/test_socketserver.py | 10 ++
Misc/NEWS | 5 +
Python/ceval.c | 22 ++++-
15 files changed, 103 insertions(+), 5 deletions(-)


diff --git a/Lib/socketserver.py b/Lib/socketserver.py
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -439,8 +439,12 @@
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
- self.server_bind()
- self.server_activate()
+ try:
+ self.server_bind()
+ self.server_activate()
+ except:
+ self.server_close()
+ raise

def server_bind(self):
"""Called by constructor to bind the socket.
diff --git a/Lib/test/test_import.py b/Lib/test/test_import/__init__.py
rename from Lib/test/test_import.py
rename to Lib/test/test_import/__init__.py
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import/__init__.py
@@ -568,7 +568,7 @@

def test_relimport_star(self):
# This will import * from .test_import.
- from . import relimport
+ from .. import relimport
self.assertTrue(hasattr(relimport, "RelativeImportTests"))

def test_issue3221(self):
@@ -1068,6 +1068,46 @@
__isolated=False)


+class CircularImportTests(unittest.TestCase):
+
+ """See the docstrings of the modules being imported for the purpose of the
+ test."""
+
+ def tearDown(self):
+ """Make sure no modules pre-exist in sys.modules which are being used to
+ test."""
+ for key in list(sys.modules.keys()):
+ if key.startswith('test.test_import.data.circular_imports'):
+ del sys.modules[key]
+
+ def test_direct(self):
+ try:
+ import test.test_import.data.circular_imports.basic
+ except ImportError:
+ self.fail('circular import through relative imports failed')
+
+ def test_indirect(self):
+ try:
+ import test.test_import.data.circular_imports.indirect
+ except ImportError:
+ self.fail('relative import in module contributing to circular '
+ 'import failed')
+
+ def test_subpackage(self):
+ try:
+ import test.test_import.data.circular_imports.subpackage
+ except ImportError:
+ self.fail('circular import involving a subpackage failed')
+
+ def test_rebinding(self):
+ try:
+ import test.test_import.data.circular_imports.rebinding as rebinding
+ except ImportError:
+ self.fail('circular import with rebinding of module attribute failed')
+ from test.test_import.data.circular_imports.subpkg import util
+ self.assertIs(util.util, rebinding.util)
+
+
if __name__ == '__main__':
# Test needs to be a package, so we can do relative imports.
unittest.main()
diff --git a/Lib/test/test_import/__main__.py b/Lib/test/test_import/__main__.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/__main__.py
@@ -0,0 +1,3 @@
+import unittest
+
+unittest.main('test.test_import')
diff --git a/Lib/test/test_import/data/circular_imports/basic.py b/Lib/test/test_import/data/circular_imports/basic.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/basic.py
@@ -0,0 +1,2 @@
+"""Circular imports through direct, relative imports."""
+from . import basic2
diff --git a/Lib/test/test_import/data/circular_imports/basic2.py b/Lib/test/test_import/data/circular_imports/basic2.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/basic2.py
@@ -0,0 +1,1 @@
+from . import basic
diff --git a/Lib/test/test_import/data/circular_imports/indirect.py b/Lib/test/test_import/data/circular_imports/indirect.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/indirect.py
@@ -0,0 +1,1 @@
+from . import basic, basic2
diff --git a/Lib/test/test_import/data/circular_imports/rebinding.py b/Lib/test/test_import/data/circular_imports/rebinding.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/rebinding.py
@@ -0,0 +1,3 @@
+"""Test the binding of names when a circular import shares the same name as an
+attribute."""
+from .rebinding2 import util
diff --git a/Lib/test/test_import/data/circular_imports/rebinding2.py b/Lib/test/test_import/data/circular_imports/rebinding2.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/rebinding2.py
@@ -0,0 +1,3 @@
+from .subpkg import util
+from . import rebinding
+util = util.util
diff --git a/Lib/test/test_import/data/circular_imports/subpackage.py b/Lib/test/test_import/data/circular_imports/subpackage.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/subpackage.py
@@ -0,0 +1,2 @@
+"""Circular import involving a sub-package."""
+from .subpkg import subpackage2
diff --git a/Lib/test/test_import/data/circular_imports/subpkg/subpackage2.py b/Lib/test/test_import/data/circular_imports/subpkg/subpackage2.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/subpkg/subpackage2.py
@@ -0,0 +1,2 @@
+#from .util import util
+from .. import subpackage
diff --git a/Lib/test/test_import/data/circular_imports/subpkg/util.py b/Lib/test/test_import/data/circular_imports/subpkg/util.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/subpkg/util.py
@@ -0,0 +1,2 @@
+def util():
+ pass
diff --git a/Lib/test/test_import/data/circular_imports/util.py b/Lib/test/test_import/data/circular_imports/util.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_import/data/circular_imports/util.py
@@ -0,0 +1,2 @@
+def util():
+ pass
diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
--- a/Lib/test/test_socketserver.py
+++ b/Lib/test/test_socketserver.py
@@ -270,6 +270,16 @@
t.join()
s.server_close()

+ def test_tcpserver_bind_leak(self):
+ # Issue #22435: the server socket wouldn't be closed if bind()/listen()
+ # failed.
+ # Create many servers for which bind() will fail, to see if this result
+ # in FD exhaustion.
+ for i in range(1024):
+ with self.assertRaises(OverflowError):
+ socketserver.TCPServer((HOST, -1),
+ socketserver.StreamRequestHandler)
+

def test_main():
if imp.lock_held():
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
Core and Builtins
-----------------

+- Issue #17636: Circular imports involving relative imports are now
+ supported.
+
- Issue #22604: Fix assertion error in debug mode when dividing a complex
number by (nan+0j).

@@ -174,6 +177,8 @@
Library
-------

+- Issue #22435: Fix a file descriptor leak when SocketServer bind fails.
+
- Issue #13096: Fixed segfault in CTypes POINTER handling of large
values.

diff --git a/Python/ceval.c b/Python/ceval.c
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4693,11 +4693,29 @@
import_from(PyObject *v, PyObject *name)
{
PyObject *x;
+ _Py_IDENTIFIER(__name__);
+ PyObject *fullmodname, *pkgname;

x = PyObject_GetAttr(v, name);
- if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ if (x != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError))
+ return x;
+ /* Issue #17636: in case this failed because of a circular relative
+ import, try to fallback on reading the module directly from
+ sys.modules. */
+ PyErr_Clear();
+ pkgname = _PyObject_GetAttrId(v, &PyId___name__);
+ if (pkgname == NULL)
+ return NULL;
+ fullmodname = PyUnicode_FromFormat("%U.%U", pkgname, name);
+ Py_DECREF(pkgname);
+ if (fullmodname == NULL)
+ return NULL;
+ x = PyDict_GetItem(PyImport_GetModuleDict(), fullmodname);
+ if (x == NULL)
PyErr_Format(PyExc_ImportError, "cannot import name %R", name);
- }
+ else
+ Py_INCREF(x);
+ Py_DECREF(fullmodname);
return x;
}
--
Repository URL: https://hg.python.org/cpython
Loading...