diff --git a/Doc/library/msvcrt.rst b/Doc/library/msvcrt.rst
index d43bb4c60f1..9fa49daf27f 100644
--- a/Doc/library/msvcrt.rst
+++ b/Doc/library/msvcrt.rst
@@ -16,6 +16,10 @@ this in the implementation of the :func:`getpass` function.
Further documentation on these functions can be found in the Platform API
documentation.
+The module implements both the normal and wide char variants of the console I/O
+api. The normal API deals only with ASCII characters and is of limited use
+for internationalized applications. The wide char API should be used where
+ever possible
.. _msvcrt-files:
@@ -94,6 +98,13 @@ Console I/O
return the keycode. The :kbd:`Control-C` keypress cannot be read with this
function.
+
+.. function:: getwch()
+
+ Wide char variant of `func:getch`, returns unicode.
+
+ ..versionadded:: 2.6
+
.. function:: getche()
@@ -101,16 +112,37 @@ Console I/O
printable character.
+.. function:: getwche()
+
+ Wide char variant of `func:getche`, returns unicode.
+
+ ..versionadded:: 2.6
+
+
.. function:: putch(char)
Print the character *char* to the console without buffering.
+
+.. function:: putwch(unicode_char)
+
+ Wide char variant of `func:putch`, accepts unicode.
+
+ ..versionadded:: 2.6
+
.. function:: ungetch(char)
Cause the character *char* to be "pushed back" into the console buffer; it will
be the next character read by :func:`getch` or :func:`getche`.
+
+.. function:: ungetwch(unicode_char)
+
+ Wide char variant of `func:ungetch`, accepts unicode.
+
+ ..versionadded:: 2.6
+
.. _msvcrt-other:
diff --git a/Lib/DocXMLRPCServer.py b/Lib/DocXMLRPCServer.py
index 08e1f10f9fa..c95210ace12 100644
--- a/Lib/DocXMLRPCServer.py
+++ b/Lib/DocXMLRPCServer.py
@@ -64,14 +64,15 @@ class ServerHTMLDoc(pydoc.HTMLDoc):
results.append(escape(text[here:]))
return ''.join(results)
- def docroutine(self, object, name=None, mod=None,
+ def docroutine(self, object, name, mod=None,
funcs={}, classes={}, methods={}, cl=None):
"""Produce HTML documentation for a function or method object."""
anchor = (cl and cl.__name__ or '') + '-' + name
note = ''
- title = '%s' % (anchor, name)
+ title = '%s' % (
+ self.escape(anchor), self.escape(name))
if inspect.ismethod(object):
args, varargs, varkw, defaults = inspect.getargspec(object)
@@ -113,6 +114,7 @@ class ServerHTMLDoc(pydoc.HTMLDoc):
fdict[key] = '#-' + key
fdict[value] = fdict[key]
+ server_name = self.escape(server_name)
head = '%s' % server_name
result = self.heading(head, '#ffffff', '#7799ee')
@@ -280,29 +282,3 @@ class DocCGIXMLRPCRequestHandler( CGIXMLRPCRequestHandler,
def __init__(self):
CGIXMLRPCRequestHandler.__init__(self)
XMLRPCDocGenerator.__init__(self)
-
-if __name__ == '__main__':
- def deg_to_rad(deg):
- """deg_to_rad(90) => 1.5707963267948966
-
- Converts an angle in degrees to an angle in radians"""
- import math
- return deg * math.pi / 180
-
- server = DocXMLRPCServer(("localhost", 8000))
-
- server.set_server_title("Math Server")
- server.set_server_name("Math XML-RPC Server")
- server.set_server_documentation("""This server supports various mathematical functions.
-
-You can use it from Python as follows:
-
->>> from xmlrpclib import ServerProxy
->>> s = ServerProxy("http://localhost:8000")
->>> s.deg_to_rad(90.0)
-1.5707963267948966""")
-
- server.register_function(deg_to_rad)
- server.register_introspection_functions()
-
- server.serve_forever()
diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py
new file mode 100644
index 00000000000..55c21434217
--- /dev/null
+++ b/Lib/test/test_docxmlrpc.py
@@ -0,0 +1,152 @@
+from DocXMLRPCServer import DocXMLRPCServer
+import httplib
+from test import test_support
+import threading
+import time
+import unittest
+import xmlrpclib
+
+PORT = None
+
+def server(evt, numrequests):
+ try:
+ serv = DocXMLRPCServer(("localhost", 0), logRequests=False)
+
+ global PORT
+ PORT = serv.socket.getsockname()[1]
+
+ # Add some documentation
+ serv.set_server_title("DocXMLRPCServer Test Documentation")
+ serv.set_server_name("DocXMLRPCServer Test Docs")
+ serv.set_server_documentation(
+"""This is an XML-RPC server's documentation, but the server can be used by
+POSTing to /RPC2. Try self.add, too.""")
+
+ # Create and register classes and functions
+ class TestClass(object):
+ def test_method(self, arg):
+ """Test method's docs. This method truly does very little."""
+ self.arg = arg
+
+ serv.register_introspection_functions()
+ serv.register_instance(TestClass())
+
+ def add(x, y):
+ """Add two instances together. This follows PEP008, but has nothing
+ to do with RFC1952. Case should matter: pEp008 and rFC1952. Things
+ that start with http and ftp should be auto-linked, too:
+ http://google.com.
+ """
+ return x + y
+
+ serv.register_function(add)
+ serv.register_function(lambda x, y: x-y)
+
+ while numrequests > 0:
+ serv.handle_request()
+ numrequests -= 1
+ except socket.timeout:
+ pass
+ finally:
+ serv.server_close()
+ PORT = None
+ evt.set()
+
+class DocXMLRPCHTTPGETServer(unittest.TestCase):
+ def setUp(self):
+ # Enable server feedback
+ DocXMLRPCServer._send_traceback_header = True
+
+ self.evt = threading.Event()
+ threading.Thread(target=server, args=(self.evt, 1)).start()
+
+ # wait for port to be assigned
+ n = 1000
+ while n > 0 and PORT is None:
+ time.sleep(0.001)
+ n -= 1
+
+ self.client = httplib.HTTPConnection("localhost:%d" % PORT)
+
+ def tearDown(self):
+ self.client.close()
+
+ self.evt.wait()
+
+ # Disable server feedback
+ DocXMLRPCServer._send_traceback_header = False
+
+ def test_valid_get_response(self):
+ self.client.request("GET", "/")
+ response = self.client.getresponse()
+
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.getheader("Content-type"), "text/html")
+
+ # Server throws an exception if we don't start to read the data
+ response.read()
+
+ def test_invalid_get_response(self):
+ self.client.request("GET", "/spam")
+ response = self.client.getresponse()
+
+ self.assertEqual(response.status, 404)
+ self.assertEqual(response.getheader("Content-type"), "text/plain")
+
+ response.read()
+
+ def test_lambda(self):
+ """Test that lambda functionality stays the same. The output produced
+ currently is, I suspect invalid because of the unencoded brackets in the
+ HTML, "".
+
+ The subtraction lambda method is tested.
+ """
+ self.client.request("GET", "/")
+ response = self.client.getresponse()
+
+ self.assert_(
+"""- <lambda>(x, y)
"""
+ in response.read())
+
+ def test_autolinking(self):
+ """Test that the server correctly automatically wraps references to PEPS
+ and RFCs with links, and that it linkifies text starting with http or
+ ftp protocol prefixes.
+
+ The documentation for the "add" method contains the test material.
+ """
+ self.client.request("GET", "/")
+ response = self.client.getresponse()
+
+ self.assert_( # This is ugly ... how can it be made better?
+"""- add(x, y)
- Add two instances together. This follows PEP008, but has nothing
\nto do with RFC1952. Case should matter: pEp008 and rFC1952. Things
\nthat start with http and ftp should be auto-linked, too:
\nhttp://google.com.
"""
+ in response.read())
+
+ def test_system_methods(self):
+ """Test the precense of three consecutive system.* methods.
+
+ This also tests their use of parameter type recognition and the systems
+ related to that process.
+ """
+ self.client.request("GET", "/")
+ response = self.client.getresponse()
+
+ self.assert_(
+"""- system.listMethods()
- system.listMethods() => [\'add\', \'subtract\', \'multiple\']
\n
\nReturns a list of the methods supported by the server.
\n - system.methodHelp(method_name)
- system.methodHelp(\'add\') => "Adds two integers together"
\n
\nReturns a string containing documentation for the specified method.
\n - system.methodSignature(method_name)
- system.methodSignature(\'add\') => [double, int, int]
\n
\nReturns a list describing the signature of the method. In the
\nabove example, the add method takes two integers as arguments
\nand returns a double result.
\n
\nThis server does NOT support system.methodSignature.
"""
+ in response.read())
+
+ def test_autolink_dotted_methods(self):
+ """Test that selfdot values are made strong automatically in the
+ documentation."""
+ self.client.request("GET", "/")
+ response = self.client.getresponse()
+
+ self.assert_("""Try self.add, too.""" in
+ response.read())
+
+def test_main():
+ test_support.run_unittest(DocXMLRPCHTTPGETServer)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/Misc/ACKS b/Misc/ACKS
index 602a4983a61..26bbb0b0b68 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -699,6 +699,7 @@ Zack Weinberg
Edward Welbourne
Cliff Wells
Rickard Westman
+Jeff Wheeler
Mats Wichmann
Truida Wiedijk
Felix Wiemann
diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c
index ae6b911d7da..a137ed0bb90 100755
--- a/PC/msvcrtmodule.c
+++ b/PC/msvcrtmodule.c
@@ -145,6 +145,22 @@ msvcrt_getch(PyObject *self, PyObject *args)
return PyString_FromStringAndSize(s, 1);
}
+static PyObject *
+msvcrt_getwch(PyObject *self, PyObject *args)
+{
+ Py_UNICODE ch;
+ Py_UNICODE u[1];
+
+ if (!PyArg_ParseTuple(args, ":getwch"))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ ch = _getwch();
+ Py_END_ALLOW_THREADS
+ u[0] = ch;
+ return PyUnicode_FromUnicode(u, 1);
+}
+
static PyObject *
msvcrt_getche(PyObject *self, PyObject *args)
{
@@ -161,6 +177,22 @@ msvcrt_getche(PyObject *self, PyObject *args)
return PyString_FromStringAndSize(s, 1);
}
+static PyObject *
+msvcrt_getwche(PyObject *self, PyObject *args)
+{
+ Py_UNICODE ch;
+ Py_UNICODE s[1];
+
+ if (!PyArg_ParseTuple(args, ":getwche"))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ ch = _getwche();
+ Py_END_ALLOW_THREADS
+ s[0] = ch;
+ return PyUnicode_FromUnicode(s, 1);
+}
+
static PyObject *
msvcrt_putch(PyObject *self, PyObject *args)
{
@@ -174,6 +206,26 @@ msvcrt_putch(PyObject *self, PyObject *args)
return Py_None;
}
+
+static PyObject *
+msvcrt_putwch(PyObject *self, PyObject *args)
+{
+ Py_UNICODE *ch;
+ int size;
+
+ if (!PyArg_ParseTuple(args, "u#:putwch", &ch, &size))
+ return NULL;
+
+ if (size == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Expected unicode string of length 1");
+ return NULL;
+ }
+ _putwch(*ch);
+ Py_RETURN_NONE;
+
+}
+
static PyObject *
msvcrt_ungetch(PyObject *self, PyObject *args)
{
@@ -188,6 +240,19 @@ msvcrt_ungetch(PyObject *self, PyObject *args)
return Py_None;
}
+static PyObject *
+msvcrt_ungetwch(PyObject *self, PyObject *args)
+{
+ Py_UNICODE ch;
+
+ if (!PyArg_ParseTuple(args, "u:ungetwch", &ch))
+ return NULL;
+
+ if (_ungetch(ch) == EOF)
+ return PyErr_SetFromErrno(PyExc_IOError);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
static void
insertint(PyObject *d, char *name, int value)
@@ -276,6 +341,10 @@ static struct PyMethodDef msvcrt_functions[] = {
{"CrtSetReportMode", msvcrt_setreportmode, METH_VARARGS},
{"set_error_mode", msvcrt_seterrormode, METH_VARARGS},
#endif
+ {"getwch", msvcrt_getwch, METH_VARARGS},
+ {"getwche", msvcrt_getwche, METH_VARARGS},
+ {"putwch", msvcrt_putwch, METH_VARARGS},
+ {"ungetwch", msvcrt_ungetwch, METH_VARARGS},
{NULL, NULL}
};