summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/collections.rst48
-rw-r--r--Doc/library/random.rst5
-rw-r--r--Lib/collections.py14
-rw-r--r--Lib/test/seq_tests.py7
-rw-r--r--Lib/test/test_collections.py10
-rw-r--r--Modules/readline.c188
-rw-r--r--Modules/socketmodule.c86
7 files changed, 151 insertions, 207 deletions
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index ba3ce31..0b856fe 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -10,7 +10,7 @@
This module implements high-performance container datatypes. Currently,
there are two datatypes, :class:`deque` and :class:`defaultdict`, and
-one datatype factory function, :func:`named_tuple`. Python already
+one datatype factory function, :func:`namedtuple`. Python already
includes built-in containers, :class:`dict`, :class:`list`,
:class:`set`, and :class:`tuple`. In addition, the optional :mod:`bsddb`
module has a :meth:`bsddb.btopen` method that can be used to create in-memory
@@ -383,14 +383,14 @@ Setting the :attr:`default_factory` to :class:`set` makes the
.. _named-tuple-factory:
-:func:`named_tuple` Factory Function for Tuples with Named Fields
+:func:`namedtuple` Factory Function for Tuples with Named Fields
-----------------------------------------------------------------
Named tuples assign meaning to each position in a tuple and allow for more readable,
self-documenting code. They can be used wherever regular tuples are used, and
they add the ability to access fields by name instead of position index.
-.. function:: named_tuple(typename, fieldnames, [verbose])
+.. function:: namedtuple(typename, fieldnames, [verbose])
Returns a new tuple subclass named *typename*. The new subclass is used to
create tuple-like objects that have fields accessable by attribute lookup as
@@ -415,7 +415,7 @@ they add the ability to access fields by name instead of position index.
Example::
- >>> Point = named_tuple('Point', 'x y', verbose=True)
+ >>> Point = namedtuple('Point', 'x y', verbose=True)
class Point(tuple):
'Point(x, y)'
__slots__ = ()
@@ -428,8 +428,8 @@ Example::
'Return a new dict mapping field names to their values'
return dict(zip(('x', 'y'), self))
def __replace__(self, field, value):
- 'Return a new Point object replacing one field with a new value'
- return Point(**dict(zip(('x', 'y'), self) + [(field, value)]))
+ 'Return a new Point object replacing specified fields with new values'
+ return Point(**dict(zip(('x', 'y'), self) + kwds.items()))
x = property(itemgetter(0))
y = property(itemgetter(1))
@@ -447,7 +447,7 @@ Example::
Named tuples are especially useful for assigning field names to result tuples returned
by the :mod:`csv` or :mod:`sqlite3` modules::
- EmployeeRecord = named_tuple('EmployeeRecord', 'name, age, title, department, paygrade')
+ EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
from itertools import starmap
import csv
@@ -486,18 +486,18 @@ two additonal methods and a read-only attribute.
>>> p.__asdict__()
{'x': 11, 'y': 22}
-.. method:: somenamedtuple.__replace__(field, value)
+.. method:: somenamedtuple.__replace__(kwargs)
- Return a new instance of the named tuple replacing the named *field* with a new *value*:
+ Return a new instance of the named tuple replacing specified fields with new values:
::
>>> p = Point(x=11, y=22)
- >>> p.__replace__('x', 33)
+ >>> p.__replace__(x=33)
Point(x=33, y=22)
- >>> for recordnum, record in inventory:
- ... inventory[recordnum] = record.replace('total', record.price * record.quantity)
+ >>> for partnum, record in inventory.items():
+ ... inventory[partnum] = record.__replace__(price=newprices[partnum], updated=time.now())
.. attribute:: somenamedtuple.__fields__
@@ -509,11 +509,31 @@ two additonal methods and a read-only attribute.
>>> p.__fields__ # view the field names
('x', 'y')
- >>> Color = named_tuple('Color', 'red green blue')
- >>> Pixel = named_tuple('Pixel', Point.__fields__ + Color.__fields__)
+ >>> Color = namedtuple('Color', 'red green blue')
+ >>> Pixel = namedtuple('Pixel', Point.__fields__ + Color.__fields__)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)'
+Since a named tuple is a regular Python class, it is easy to add or change
+functionality. For example, the display format can be changed by overriding
+the :meth:`__repr__` method:
+
+::
+
+ >>> Point = namedtuple('Point', 'x y')
+ >>> Point.__repr__ = lambda self: 'Point(%.3f, %.3f)' % self
+ >>> Point(x=10, y=20)
+ Point(10.000, 20.000)
+
+Default values can be implemented by starting with a prototype instance
+and customizing it with :meth:`__replace__`:
+
+::
+
+ >>> Account = namedtuple('Account', 'owner balance transaction_count')
+ >>> model_account = Account('<owner name>', 0.0, 0)
+ >>> johns_account = model_account.__replace__(owner='John')
+
.. rubric:: Footnotes
.. [#] For information on the star-operator see
diff --git a/Doc/library/random.rst b/Doc/library/random.rst
index f0d5d12..9b02003 100644
--- a/Doc/library/random.rst
+++ b/Doc/library/random.rst
@@ -282,8 +282,3 @@ Examples of basic usage::
Wichmann, B. A. & Hill, I. D., "Algorithm AS 183: An efficient and portable
pseudo-random number generator", Applied Statistics 31 (1982) 188-190.
- http://www.npl.co.uk/ssfm/download/abstracts.html#196
- A modern variation of the Wichmann-Hill generator that greatly increases the
- period, and passes now-standard statistical tests that the original generator
- failed.
-
diff --git a/Lib/collections.py b/Lib/collections.py
index 90ed776..7b23948 100644
--- a/Lib/collections.py
+++ b/Lib/collections.py
@@ -30,7 +30,7 @@ def namedtuple(typename, field_names, verbose=False):
11
>>> Point(**d) # convert from a dictionary
Point(x=11, y=22)
- >>> p.__replace__('x', 100) # __replace__() is like str.replace() but targets a named field
+ >>> p.__replace__(x=100) # __replace__() is like str.replace() but targets named fields
Point(x=100, y=22)
"""
@@ -60,7 +60,7 @@ def namedtuple(typename, field_names, verbose=False):
template = '''class %(typename)s(tuple):
'%(typename)s(%(argtxt)s)'
__slots__ = ()
- __fields__ = %(field_names)r
+ __fields__ = property(lambda self: %(field_names)r)
def __new__(cls, %(argtxt)s):
return tuple.__new__(cls, (%(argtxt)s))
def __repr__(self):
@@ -68,9 +68,9 @@ def namedtuple(typename, field_names, verbose=False):
def __asdict__(self, dict=dict, zip=zip):
'Return a new dict mapping field names to their values'
return dict(zip(%(field_names)r, self))
- def __replace__(self, field, value, dict=dict, zip=zip):
- 'Return a new %(typename)s object replacing one field with a new value'
- return %(typename)s(**dict(list(zip(%(field_names)r, self)) + [(field, value)])) \n''' % locals()
+ def __replace__(self, **kwds):
+ 'Return a new %(typename)s object replacing specified fields with new values'
+ return %(typename)s(**dict(zip(%(field_names)r, self) + kwds.items())) \n''' % locals()
for i, name in enumerate(field_names):
template += ' %s = property(itemgetter(%d))\n' % (name, i)
if verbose:
@@ -103,6 +103,10 @@ if __name__ == '__main__':
p = Point(x=10, y=20)
assert p == loads(dumps(p))
+ # test and demonstrate ability to override methods
+ Point.__repr__ = lambda self: 'Point(%.3f, %.3f)' % self
+ print p
+
import doctest
TestResults = namedtuple('TestResults', 'failed attempted')
print(TestResults(*doctest.testmod()))
diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py
index eb6d141..ebd6157 100644
--- a/Lib/test/seq_tests.py
+++ b/Lib/test/seq_tests.py
@@ -304,6 +304,13 @@ class CommonTest(unittest.TestCase):
self.assertEqual(self.type2test(s)*(-4), self.type2test([]))
self.assertEqual(id(s), id(s*1))
+ def test_bigrepeat(self):
+ x = self.type2test([0])
+ x *= 2**16
+ self.assertRaises(MemoryError, x.__mul__, 2**16)
+ if hasattr(x, '__imul__'):
+ self.assertRaises(MemoryError, x.__imul__, 2**16)
+
def test_subscript(self):
a = self.type2test([10, 11])
self.assertEqual(a.__getitem__(0), 10)
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 86b47de..0243134 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -48,9 +48,17 @@ class TestNamedTuple(unittest.TestCase):
self.assert_('__dict__' not in dir(p)) # verify instance has no dict
self.assert_('__weakref__' not in dir(p))
self.assertEqual(p.__fields__, ('x', 'y')) # test __fields__ attribute
- self.assertEqual(p.__replace__('x', 1), (1, 22)) # test __replace__ method
+ self.assertEqual(p.__replace__(x=1), (1, 22)) # test __replace__ method
self.assertEqual(p.__asdict__(), dict(x=11, y=22)) # test __dict__ method
+ # Verify that __fields__ is read-only
+ try:
+ p.__fields__ = ('F1' ,'F2')
+ except AttributeError:
+ pass
+ else:
+ self.fail('The __fields__ attribute needs to be read-only')
+
# verify that field string can have commas
Point = namedtuple('Point', 'x, y')
p = Point(x=11, y=22)
diff --git a/Modules/readline.c b/Modules/readline.c
index 9052937..c915327 100644
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -59,8 +59,7 @@ parse_and_bind(PyObject *self, PyObject *args)
strcpy(copy, s);
rl_parse_and_bind(copy);
free(copy); /* Free the copy */
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_parse_and_bind,
@@ -79,8 +78,7 @@ read_init_file(PyObject *self, PyObject *args)
errno = rl_read_init_file(s);
if (errno)
return PyErr_SetFromErrno(PyExc_IOError);
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_read_init_file,
@@ -100,8 +98,7 @@ read_history_file(PyObject *self, PyObject *args)
errno = read_history(s);
if (errno)
return PyErr_SetFromErrno(PyExc_IOError);
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static int _history_length = -1; /* do not truncate history by default */
@@ -124,8 +121,7 @@ write_history_file(PyObject *self, PyObject *args)
history_truncate_file(s, _history_length);
if (errno)
return PyErr_SetFromErrno(PyExc_IOError);
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_write_history_file,
@@ -143,8 +139,7 @@ set_history_length(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "i:set_history_length", &length))
return NULL;
_history_length = length;
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(set_history_length_doc,
@@ -195,8 +190,7 @@ set_hook(const char *funcname, PyObject **hook_var, PyObject *args)
PyErr_SetString(PyExc_TypeError, buf);
return NULL;
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
@@ -218,7 +212,7 @@ set_completion_display_matches_hook(PyObject *self, PyObject *args)
/* We cannot set this hook globally, since it replaces the
default completion display. */
rl_completion_display_matches_hook =
- completion_display_matches_hook ?
+ completion_display_matches_hook ?
(rl_compdisp_func_t *)on_completion_display_matches_hook : 0;
#endif
return result;
@@ -325,8 +319,7 @@ set_completer_delims(PyObject *self, PyObject *args)
}
free((void*)rl_completer_word_break_characters);
rl_completer_word_break_characters = strdup(break_chars);
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_set_completer_delims,
@@ -336,32 +329,31 @@ set the readline word delimiters for tab-completion");
static PyObject *
py_remove_history(PyObject *self, PyObject *args)
{
- int entry_number;
- HIST_ENTRY *entry;
-
- if (!PyArg_ParseTuple(args, "i:remove_history", &entry_number))
- return NULL;
- if (entry_number < 0) {
- PyErr_SetString(PyExc_ValueError,
- "History index cannot be negative");
- return NULL;
- }
- entry = remove_history(entry_number);
- if (!entry) {
- PyErr_Format(PyExc_ValueError,
- "No history item at position %d",
- entry_number);
- return NULL;
- }
- /* free memory allocated for the history entry */
- if (entry->line)
- free(entry->line);
- if (entry->data)
- free(entry->data);
- free(entry);
-
- Py_INCREF(Py_None);
- return Py_None;
+ int entry_number;
+ HIST_ENTRY *entry;
+
+ if (!PyArg_ParseTuple(args, "i:remove_history", &entry_number))
+ return NULL;
+ if (entry_number < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "History index cannot be negative");
+ return NULL;
+ }
+ entry = remove_history(entry_number);
+ if (!entry) {
+ PyErr_Format(PyExc_ValueError,
+ "No history item at position %d",
+ entry_number);
+ return NULL;
+ }
+ /* free memory allocated for the history entry */
+ if (entry->line)
+ free(entry->line);
+ if (entry->data)
+ free(entry->data);
+ free(entry);
+
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_remove_history,
@@ -371,34 +363,34 @@ remove history item given by its position");
static PyObject *
py_replace_history(PyObject *self, PyObject *args)
{
- int entry_number;
- char *line;
- HIST_ENTRY *old_entry;
-
- if (!PyArg_ParseTuple(args, "is:replace_history", &entry_number, &line)) {
- return NULL;
- }
- if (entry_number < 0) {
- PyErr_SetString(PyExc_ValueError,
- "History index cannot be negative");
- return NULL;
- }
- old_entry = replace_history_entry(entry_number, line, (void *)NULL);
- if (!old_entry) {
- PyErr_Format(PyExc_ValueError,
- "No history item at position %d",
- entry_number);
- return NULL;
- }
- /* free memory allocated for the old history entry */
- if (old_entry->line)
- free(old_entry->line);
- if (old_entry->data)
- free(old_entry->data);
- free(old_entry);
-
- Py_INCREF(Py_None);
- return Py_None;
+ int entry_number;
+ char *line;
+ HIST_ENTRY *old_entry;
+
+ if (!PyArg_ParseTuple(args, "is:replace_history", &entry_number,
+ &line)) {
+ return NULL;
+ }
+ if (entry_number < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "History index cannot be negative");
+ return NULL;
+ }
+ old_entry = replace_history_entry(entry_number, line, (void *)NULL);
+ if (!old_entry) {
+ PyErr_Format(PyExc_ValueError,
+ "No history item at position %d",
+ entry_number);
+ return NULL;
+ }
+ /* free memory allocated for the old history entry */
+ if (old_entry->line)
+ free(old_entry->line);
+ if (old_entry->data)
+ free(old_entry->data);
+ free(old_entry);
+
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_replace_history,
@@ -416,8 +408,7 @@ py_add_history(PyObject *self, PyObject *args)
return NULL;
}
add_history(line);
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_add_history,
@@ -458,8 +449,7 @@ static PyObject *
get_completer(PyObject *self, PyObject *noargs)
{
if (completer == NULL) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
Py_INCREF(completer);
return completer;
@@ -483,8 +473,7 @@ get_history_item(PyObject *self, PyObject *args)
if ((hist_ent = history_get(idx)))
return PyUnicode_FromString(hist_ent->line);
else {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
}
@@ -530,8 +519,7 @@ static PyObject *
py_clear_history(PyObject *self, PyObject *noarg)
{
clear_history();
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_clear_history,
@@ -549,8 +537,7 @@ insert_text(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:insert_text", &s))
return NULL;
rl_insert_text(s);
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_insert_text,
@@ -564,8 +551,7 @@ static PyObject *
redisplay(PyObject *self, PyObject *noarg)
{
rl_redisplay();
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(doc_redisplay,
@@ -591,9 +577,9 @@ static struct PyMethodDef readline_methods[] =
METH_VARARGS, doc_get_history_item},
{"get_current_history_length", (PyCFunction)get_current_history_length,
METH_NOARGS, doc_get_current_history_length},
- {"set_history_length", set_history_length,
+ {"set_history_length", set_history_length,
METH_VARARGS, set_history_length_doc},
- {"get_history_length", get_history_length,
+ {"get_history_length", get_history_length,
METH_NOARGS, get_history_length_doc},
{"set_completer", set_completer, METH_VARARGS, doc_set_completer},
{"get_completer", get_completer, METH_NOARGS, doc_get_completer},
@@ -605,8 +591,8 @@ static struct PyMethodDef readline_methods[] =
{"set_completer_delims", set_completer_delims,
METH_VARARGS, doc_set_completer_delims},
{"add_history", py_add_history, METH_VARARGS, doc_add_history},
- {"remove_history_item", py_remove_history, METH_VARARGS, doc_remove_history},
- {"replace_history_item", py_replace_history, METH_VARARGS, doc_replace_history},
+ {"remove_history_item", py_remove_history, METH_VARARGS, doc_remove_history},
+ {"replace_history_item", py_replace_history, METH_VARARGS, doc_replace_history},
{"get_completer_delims", get_completer_delims,
METH_NOARGS, doc_get_completer_delims},
@@ -633,7 +619,7 @@ on_hook(PyObject *func)
int result = 0;
if (func != NULL) {
PyObject *r;
-#ifdef WITH_THREAD
+#ifdef WITH_THREAD
PyGILState_STATE gilstate = PyGILState_Ensure();
#endif
r = PyObject_CallFunction(func, NULL);
@@ -652,7 +638,7 @@ on_hook(PyObject *func)
PyErr_Clear();
Py_XDECREF(r);
done:
-#ifdef WITH_THREAD
+#ifdef WITH_THREAD
PyGILState_Release(gilstate);
#endif
return result;
@@ -682,37 +668,37 @@ on_completion_display_matches_hook(char **matches,
int num_matches, int max_length)
{
int i;
- PyObject *m, *s;
- PyObject *r;
+ PyObject *m=NULL, *s=NULL, *r=NULL;
#ifdef WITH_THREAD
PyGILState_STATE gilstate = PyGILState_Ensure();
#endif
m = PyList_New(num_matches);
+ if (m == NULL)
+ goto error;
for (i = 0; i < num_matches; i++) {
s = PyUnicode_FromString(matches[i+1]);
- if (s) {
- PyList_SetItem(m, i, s);
- }
- else {
+ if (s == NULL)
+ goto error;
+ if (PyList_SetItem(m, i, s) == -1)
goto error;
- }
}
r = PyObject_CallFunction(completion_display_matches_hook,
"sOi", matches[0], m, max_length);
Py_DECREF(m), m=NULL;
-
+
if (r == NULL ||
(r != Py_None && PyInt_AsLong(r) == -1 && PyErr_Occurred())) {
goto error;
}
+ Py_XDECREF(r), r=NULL;
- Py_DECREF(r);
- goto done;
- error:
- PyErr_Clear();
- Py_XDECREF(r);
- done:
+ if (0) {
+ error:
+ PyErr_Clear();
+ Py_XDECREF(m);
+ Py_XDECREF(r);
+ }
#ifdef WITH_THREAD
PyGILState_Release(gilstate);
#endif
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 2621a9e..30e8d22 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -450,87 +450,11 @@ set_error(void)
{
#ifdef MS_WINDOWS
int err_no = WSAGetLastError();
- static struct {
- int no;
- const char *msg;
- } *msgp, msgs[] = {
- {WSAEINTR, "Interrupted system call"},
- {WSAEBADF, "Bad file descriptor"},
- {WSAEACCES, "Permission denied"},
- {WSAEFAULT, "Bad address"},
- {WSAEINVAL, "Invalid argument"},
- {WSAEMFILE, "Too many open files"},
- {WSAEWOULDBLOCK,
- "The socket operation could not complete "
- "without blocking"},
- {WSAEINPROGRESS, "Operation now in progress"},
- {WSAEALREADY, "Operation already in progress"},
- {WSAENOTSOCK, "Socket operation on non-socket"},
- {WSAEDESTADDRREQ, "Destination address required"},
- {WSAEMSGSIZE, "Message too long"},
- {WSAEPROTOTYPE, "Protocol wrong type for socket"},
- {WSAENOPROTOOPT, "Protocol not available"},
- {WSAEPROTONOSUPPORT, "Protocol not supported"},
- {WSAESOCKTNOSUPPORT, "Socket type not supported"},
- {WSAEOPNOTSUPP, "Operation not supported"},
- {WSAEPFNOSUPPORT, "Protocol family not supported"},
- {WSAEAFNOSUPPORT, "Address family not supported"},
- {WSAEADDRINUSE, "Address already in use"},
- {WSAEADDRNOTAVAIL, "Can't assign requested address"},
- {WSAENETDOWN, "Network is down"},
- {WSAENETUNREACH, "Network is unreachable"},
- {WSAENETRESET, "Network dropped connection on reset"},
- {WSAECONNABORTED, "Software caused connection abort"},
- {WSAECONNRESET, "Connection reset by peer"},
- {WSAENOBUFS, "No buffer space available"},
- {WSAEISCONN, "Socket is already connected"},
- {WSAENOTCONN, "Socket is not connected"},
- {WSAESHUTDOWN, "Can't send after socket shutdown"},
- {WSAETOOMANYREFS, "Too many references: can't splice"},
- {WSAETIMEDOUT, "Operation timed out"},
- {WSAECONNREFUSED, "Connection refused"},
- {WSAELOOP, "Too many levels of symbolic links"},
- {WSAENAMETOOLONG, "File name too long"},
- {WSAEHOSTDOWN, "Host is down"},
- {WSAEHOSTUNREACH, "No route to host"},
- {WSAENOTEMPTY, "Directory not empty"},
- {WSAEPROCLIM, "Too many processes"},
- {WSAEUSERS, "Too many users"},
- {WSAEDQUOT, "Disc quota exceeded"},
- {WSAESTALE, "Stale NFS file handle"},
- {WSAEREMOTE, "Too many levels of remote in path"},
- {WSASYSNOTREADY, "Network subsystem is unvailable"},
- {WSAVERNOTSUPPORTED, "WinSock version is not supported"},
- {WSANOTINITIALISED,
- "Successful WSAStartup() not yet performed"},
- {WSAEDISCON, "Graceful shutdown in progress"},
- /* Resolver errors */
- {WSAHOST_NOT_FOUND, "No such host is known"},
- {WSATRY_AGAIN, "Host not found, or server failed"},
- {WSANO_RECOVERY, "Unexpected server error encountered"},
- {WSANO_DATA, "Valid name without requested data"},
- {WSANO_ADDRESS, "No address, look for MX record"},
- {0, NULL}
- };
- if (err_no) {
- PyObject *v;
- const char *msg = "winsock error";
-
- for (msgp = msgs; msgp->msg; msgp++) {
- if (err_no == msgp->no) {
- msg = msgp->msg;
- break;
- }
- }
-
- v = Py_BuildValue("(is)", err_no, msg);
- if (v != NULL) {
- PyErr_SetObject(socket_error, v);
- Py_DECREF(v);
- }
- return NULL;
- }
- else
+ /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which
+ recognizes the error codes used by both GetLastError() and
+ WSAGetLastError */
+ if (err_no)
+ return PyErr_SetExcFromWindowsErr(socket_error, err_no);
#endif
#if defined(PYOS_OS2) && !defined(PYCC_GCC)