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} };