[Python-checkins] cpython (merge default -> default): Merge.
stefan.krah
python-checkins at python.org
Sat Apr 7 16:12:26 CEST 2012
http://hg.python.org/cpython/rev/4862619fe28b
changeset: 76152:4862619fe28b
parent: 76151:a80a579282c7
parent: 76150:51b4bddd0e92
user: Stefan Krah <skrah at bytereef.org>
date: Sat Apr 07 16:10:04 2012 +0200
summary:
Merge.
files:
.hgtags | 2 +
Doc/library/socket.rst | 25 ++
Lib/importlib/test/import_/test_packages.py | 6 +-
Lib/socket.py | 10 +-
Lib/test/test_asyncore.py | 7 +-
Lib/test/test_site.py | 5 +-
Lib/test/test_socket.py | 105 ++++++++++
Lib/test/test_tools.py | 27 ++
Misc/NEWS | 5 +
Modules/_io/textio.c | 2 +-
Modules/socketmodule.c | 73 ++++++-
Tools/scripts/pdeps.py | 10 +-
12 files changed, 258 insertions(+), 19 deletions(-)
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -78,6 +78,8 @@
32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1
c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4
ee26aca3219cf4bb0b93352e83edcc9cb28c7802 v3.1.5rc1
+75db2bc69fc9a3e4801e94e3e19801cb096208d8 v3.1.5rc2
+7395330e495ec3316862ca1f6ce0aaf7bdf6785b v3.1.5
b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1
56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2
da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -680,6 +680,16 @@
.. versionadded:: 3.3
+.. function:: fromshare(data)
+
+ Instantiate a socket from data obtained from :meth:`~socket.share`.
+ The socket is assumed to be in blocking mode.
+
+ Availability: Windows.
+
+ .. versionadded:: 3.3
+
+
.. data:: SocketType
This is a Python type object that represents the socket object type. It is the
@@ -1082,6 +1092,21 @@
are disallowed. If *how* is :const:`SHUT_RDWR`, further sends and receives are
disallowed.
+
+.. method:: socket.share(process_id)
+
+ :platform: Windows
+
+ Duplacet a socket and prepare it for sharing with a target process. The
+ target process must be provided with *process_id*. The resulting bytes object
+ can then be passed to the target process using some form of interprocess
+ communication and the socket can be recreated there using :func:`fromshare`.
+ Once this method has been called, it is safe to close the socket since
+ the operating system has already duplicated it for the target process.
+
+ .. versionadded:: 3.3
+
+
Note that there are no methods :meth:`read` or :meth:`write`; use
:meth:`~socket.recv` and :meth:`~socket.send` without *flags* argument instead.
diff --git a/Lib/importlib/test/import_/test_packages.py b/Lib/importlib/test/import_/test_packages.py
--- a/Lib/importlib/test/import_/test_packages.py
+++ b/Lib/importlib/test/import_/test_packages.py
@@ -3,6 +3,7 @@
import sys
import unittest
import importlib
+from test import support
class ParentModuleTests(unittest.TestCase):
@@ -38,7 +39,10 @@
module_code={'mod': module_injection})
with mock_modules as mock:
with util.import_state(meta_path=[mock]):
- submodule = import_util.import_(subname)
+ try:
+ submodule = import_util.import_(subname)
+ finally:
+ support.unload(subname)
def test_main():
diff --git a/Lib/socket.py b/Lib/socket.py
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -12,6 +12,7 @@
socket() -- create a new socket object
socketpair() -- create a pair of new socket objects [*]
fromfd() -- create a socket object from an open file descriptor [*]
+fromshare() -- create a socket object from data received from socket.share() [*]
gethostname() -- return the current hostname
gethostbyname() -- map a hostname to its IP number
gethostbyaddr() -- map an IP number or hostname to DNS info
@@ -209,7 +210,6 @@
self._closed = True
return super().detach()
-
def fromfd(fd, family, type, proto=0):
""" fromfd(fd, family, type[, proto]) -> socket object
@@ -219,6 +219,14 @@
nfd = dup(fd)
return socket(family, type, proto, nfd)
+if hasattr(_socket.socket, "share"):
+ def fromshare(info):
+ """ fromshare(info) -> socket object
+
+ Create a socket object from a the bytes object returned by
+ socket.share(pid).
+ """
+ return socket(0, 0, 0, info)
if hasattr(_socket, "socketpair"):
diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py
--- a/Lib/test/test_asyncore.py
+++ b/Lib/test/test_asyncore.py
@@ -74,15 +74,16 @@
pass
else:
n = 200
- while n > 0:
- r, w, e = select.select([conn], [], [])
+ start = time.time()
+ while n > 0 and time.time() - start < 3.0:
+ r, w, e = select.select([conn], [], [], 0.1)
if r:
+ n -= 1
data = conn.recv(10)
# keep everything except for the newline terminator
buf.write(data.replace(b'\n', b''))
if b'\n' in data:
break
- n -= 1
time.sleep(0.01)
conn.close()
diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py
--- a/Lib/test/test_site.py
+++ b/Lib/test/test_site.py
@@ -39,6 +39,7 @@
self.old_base = site.USER_BASE
self.old_site = site.USER_SITE
self.old_prefixes = site.PREFIXES
+ self.original_vars = sysconfig._CONFIG_VARS
self.old_vars = copy(sysconfig._CONFIG_VARS)
def tearDown(self):
@@ -47,7 +48,9 @@
site.USER_BASE = self.old_base
site.USER_SITE = self.old_site
site.PREFIXES = self.old_prefixes
- sysconfig._CONFIG_VARS = self.old_vars
+ sysconfig._CONFIG_VARS = self.original_vars
+ sysconfig._CONFIG_VARS.clear()
+ sysconfig._CONFIG_VARS.update(self.old_vars)
def test_makepath(self):
# Test makepath() have an absolute path for its first return value
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -26,6 +26,10 @@
import fcntl
except ImportError:
fcntl = False
+try:
+ import multiprocessing
+except ImportError:
+ multiprocessing = False
HOST = support.HOST
MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return
@@ -4643,6 +4647,106 @@
socket.setdefaulttimeout(t)
+ at unittest.skipUnless(os.name == "nt", "Windows specific")
+ at unittest.skipUnless(multiprocessing, "need multiprocessing")
+class TestSocketSharing(SocketTCPTest):
+ # This must be classmethod and not staticmethod or multiprocessing
+ # won't be able to bootstrap it.
+ @classmethod
+ def remoteProcessServer(cls, q):
+ # Recreate socket from shared data
+ sdata = q.get()
+ message = q.get()
+
+ s = socket.fromshare(sdata)
+ s2, c = s.accept()
+
+ # Send the message
+ s2.sendall(message)
+ s2.close()
+ s.close()
+
+ def testShare(self):
+ # Transfer the listening server socket to another process
+ # and service it from there.
+
+ # Create process:
+ q = multiprocessing.Queue()
+ p = multiprocessing.Process(target=self.remoteProcessServer, args=(q,))
+ p.start()
+
+ # Get the shared socket data
+ data = self.serv.share(p.pid)
+
+ # Pass the shared socket to the other process
+ addr = self.serv.getsockname()
+ self.serv.close()
+ q.put(data)
+
+ # The data that the server will send us
+ message = b"slapmahfro"
+ q.put(message)
+
+ # Connect
+ s = socket.create_connection(addr)
+ # listen for the data
+ m = []
+ while True:
+ data = s.recv(100)
+ if not data:
+ break
+ m.append(data)
+ s.close()
+ received = b"".join(m)
+ self.assertEqual(received, message)
+ p.join()
+
+ def testShareLength(self):
+ data = self.serv.share(os.getpid())
+ self.assertRaises(ValueError, socket.fromshare, data[:-1])
+ self.assertRaises(ValueError, socket.fromshare, data+b"foo")
+
+ def compareSockets(self, org, other):
+ # socket sharing is expected to work only for blocking socket
+ # since the internal python timout value isn't transfered.
+ self.assertEqual(org.gettimeout(), None)
+ self.assertEqual(org.gettimeout(), other.gettimeout())
+
+ self.assertEqual(org.family, other.family)
+ self.assertEqual(org.type, other.type)
+ # If the user specified "0" for proto, then
+ # internally windows will have picked the correct value.
+ # Python introspection on the socket however will still return
+ # 0. For the shared socket, the python value is recreated
+ # from the actual value, so it may not compare correctly.
+ if org.proto != 0:
+ self.assertEqual(org.proto, other.proto)
+
+ def testShareLocal(self):
+ data = self.serv.share(os.getpid())
+ s = socket.fromshare(data)
+ try:
+ self.compareSockets(self.serv, s)
+ finally:
+ s.close()
+
+ def testTypes(self):
+ families = [socket.AF_INET, socket.AF_INET6]
+ types = [socket.SOCK_STREAM, socket.SOCK_DGRAM]
+ for f in families:
+ for t in types:
+ source = socket.socket(f, t)
+ try:
+ data = source.share(os.getpid())
+ shared = socket.fromshare(data)
+ try:
+ self.compareSockets(source, shared)
+ finally:
+ shared.close()
+ finally:
+ source.close()
+
+
def test_main():
tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest,
TestExceptions, BufferIOTest, BasicTCPTest2, BasicUDPTest, UDPTimeoutTest ]
@@ -4699,6 +4803,7 @@
# These are slow when setitimer() is not available
InterruptedRecvTimeoutTest,
InterruptedSendTimeoutTest,
+ TestSocketSharing,
])
thread_info = support.threading_setup()
diff --git a/Lib/test/test_tools.py b/Lib/test/test_tools.py
--- a/Lib/test/test_tools.py
+++ b/Lib/test/test_tools.py
@@ -6,8 +6,10 @@
import os
import sys
+import imp
import unittest
import sysconfig
+import tempfile
from test import support
from test.script_helper import assert_python_ok
@@ -72,6 +74,31 @@
import analyze_dxp
+class PdepsTests(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(self):
+ path = os.path.join(scriptsdir, 'pdeps.py')
+ self.pdeps = imp.load_source('pdeps', path)
+
+ @classmethod
+ def tearDownClass(self):
+ if 'pdeps' in sys.modules:
+ del sys.modules['pdeps']
+
+ def test_process_errors(self):
+ # Issue #14492: m_import.match(line) can be None.
+ with tempfile.TemporaryDirectory() as tmpdir:
+ fn = os.path.join(tmpdir, 'foo')
+ with open(fn, 'w') as stream:
+ stream.write("#!/this/will/fail")
+ self.pdeps.process(fn, {})
+
+ def test_inverse_attribute_error(self):
+ # Issue #14492: this used to fail with an AttributeError.
+ self.pdeps.inverse({'a': []})
+
+
def test_main():
support.run_unittest(*[obj for obj in globals().values()
if isinstance(obj, type)])
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -19,6 +19,8 @@
Library
-------
+- Don't Py_DECREF NULL variable in io.IncrementalNewlineDecoder.
+
- Issue #8515: Set __file__ when run file in IDLE.
Initial patch by Bruce Frederiksen.
@@ -230,6 +232,9 @@
- Issue #14210: pdb now has tab-completion not only for command names, but
also for their arguments, wherever possible.
+- Issue #14310: Sockets can now be with other processes on Windows using
+ the api socket.socket.share() and socket.fromshare().
+
Build
-----
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -460,7 +460,7 @@
output = PyUnicode_FromKindAndData(kind, translated, out);
PyMem_Free(translated);
if (!output)
- goto error;
+ return NULL;
}
self->seennl |= seennl;
}
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -3771,6 +3771,34 @@
Control the socket with WSAIoctl syscall. Currently supported 'cmd' values are\n\
SIO_RCVALL: 'option' must be one of the socket.RCVALL_* constants.\n\
SIO_KEEPALIVE_VALS: 'option' is a tuple of (onoff, timeout, interval).");
+#endif
+
+#if defined(MS_WINDOWS)
+static PyObject*
+sock_share(PySocketSockObject *s, PyObject *arg)
+{
+ WSAPROTOCOL_INFO info;
+ DWORD processId;
+ int result;
+
+ if (!PyArg_ParseTuple(arg, "I", &processId))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = WSADuplicateSocket(s->sock_fd, processId, &info);
+ Py_END_ALLOW_THREADS
+ if (result == SOCKET_ERROR)
+ return set_error();
+ return PyBytes_FromStringAndSize((const char*)&info, sizeof(info));
+}
+PyDoc_STRVAR(sock_share_doc,
+"share(process_id) -> bytes\n\
+\n\
+Share the socket with another process. The target process id\n\
+must be provided and the resulting bytes object passed to the target\n\
+process. There the shared socket can be instantiated by calling\n\
+socket.fromshare().");
+
#endif
@@ -3803,6 +3831,10 @@
{"ioctl", (PyCFunction)sock_ioctl, METH_VARARGS,
sock_ioctl_doc},
#endif
+#if defined(MS_WINDOWS)
+ {"share", (PyCFunction)sock_share, METH_VARARGS,
+ sock_share_doc},
+#endif
{"listen", (PyCFunction)sock_listen, METH_O,
listen_doc},
{"recv", (PyCFunction)sock_recv, METH_VARARGS,
@@ -3930,13 +3962,40 @@
return -1;
if (fdobj != NULL && fdobj != Py_None) {
- fd = PyLong_AsSocket_t(fdobj);
- if (fd == (SOCKET_T)(-1) && PyErr_Occurred())
- return -1;
- if (fd == INVALID_SOCKET) {
- PyErr_SetString(PyExc_ValueError,
- "can't use invalid socket value");
- return -1;
+#ifdef MS_WINDOWS
+ /* recreate a socket that was duplicated */
+ if (PyBytes_Check(fdobj)) {
+ WSAPROTOCOL_INFO info;
+ if (PyBytes_GET_SIZE(fdobj) != sizeof(info)) {
+ PyErr_Format(PyExc_ValueError,
+ "socket descriptor string has wrong size, "
+ "should be %zu bytes.", sizeof(info));
+ return -1;
+ }
+ memcpy(&info, PyBytes_AS_STRING(fdobj), sizeof(info));
+ Py_BEGIN_ALLOW_THREADS
+ fd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO, &info, 0, WSA_FLAG_OVERLAPPED);
+ Py_END_ALLOW_THREADS
+ if (fd == INVALID_SOCKET) {
+ set_error();
+ return -1;
+ }
+ family = info.iAddressFamily;
+ type = info.iSocketType;
+ proto = info.iProtocol;
+ }
+ else
+#endif
+ {
+ fd = PyLong_AsSocket_t(fdobj);
+ if (fd == (SOCKET_T)(-1) && PyErr_Occurred())
+ return -1;
+ if (fd == INVALID_SOCKET) {
+ PyErr_SetString(PyExc_ValueError,
+ "can't use invalid socket value");
+ return -1;
+ }
}
}
else {
diff --git a/Tools/scripts/pdeps.py b/Tools/scripts/pdeps.py
--- a/Tools/scripts/pdeps.py
+++ b/Tools/scripts/pdeps.py
@@ -76,10 +76,9 @@
nextline = fp.readline()
if not nextline: break
line = line[:-1] + nextline
- if m_import.match(line) >= 0:
- (a, b), (a1, b1) = m_import.regs[:2]
- elif m_from.match(line) >= 0:
- (a, b), (a1, b1) = m_from.regs[:2]
+ m_found = m_import.match(line) or m_from.match(line)
+ if m_found:
+ (a, b), (a1, b1) = m_found.regs[:2]
else: continue
words = line[a1:b1].split(',')
# print '#', line, words
@@ -87,6 +86,7 @@
word = word.strip()
if word not in list:
list.append(word)
+ fp.close()
# Compute closure (this is in fact totally general)
@@ -123,7 +123,7 @@
def inverse(table):
inv = {}
for key in table.keys():
- if not inv.has_key(key):
+ if key not in inv:
inv[key] = []
for item in table[key]:
store(inv, item, key)
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list