diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index bb15322067245e..88eb0be9de88b8 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -524,14 +524,9 @@ FTP_TLS objects :class:`!FTP_TLS` class inherits from :class:`FTP`, defining these additional methods and attributes: - .. attribute:: FTP_TLS.ssl_version - - The SSL version to use (defaults to :data:`ssl.PROTOCOL_SSLv23`). - .. method:: FTP_TLS.auth() - Set up a secure control connection by using TLS or SSL, depending on what - is specified in the :attr:`ssl_version` attribute. + Set up a secure control connection by using TLS. .. versionchanged:: 3.4 The method now supports hostname check with @@ -548,7 +543,7 @@ FTP_TLS objects .. method:: FTP_TLS.prot_p() - Set up secure data connection. + Set up secure data connection by using TLS. .. method:: FTP_TLS.prot_c() diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 5d64af43b69828..ae197f765d1e16 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1844,6 +1844,14 @@ expression support in the :mod:`re` module). lowercase letter ``'ß'`` is equivalent to ``"ss"``. Since it is already lowercase, :meth:`lower` would do nothing to ``'ß'``; :meth:`casefold` converts it to ``"ss"``. + For example: + + .. doctest:: + + >>> 'straße'.lower() + 'straße' + >>> 'straße'.casefold() + 'strasse' The casefolding algorithm is `described in section 3.13.3 'Default Case Folding' of the Unicode Standard @@ -2300,7 +2308,12 @@ expression support in the :mod:`re` module). .. method:: str.lower() Return a copy of the string with all the cased characters [4]_ converted to - lowercase. + lowercase. For example: + + .. doctest:: + + >>> 'Lower Method Example'.lower() + 'lower method example' The lowercasing algorithm used is `described in section 3.13.2 'Default Case Conversion' of the Unicode Standard diff --git a/Include/exports.h b/Include/exports.h index 62feb09ed2b433..97a674ec2403a4 100644 --- a/Include/exports.h +++ b/Include/exports.h @@ -35,6 +35,12 @@ #define Py_EXPORTED_SYMBOL #define Py_LOCAL_SYMBOL #endif + /* module init functions outside the core must be exported */ + #if defined(Py_BUILD_CORE) + #define _PyINIT_EXPORTED_SYMBOL Py_EXPORTED_SYMBOL + #else + #define _PyINIT_EXPORTED_SYMBOL __declspec(dllexport) + #endif #else /* * If we only ever used gcc >= 5, we could use __has_attribute(visibility) @@ -52,19 +58,16 @@ #define Py_EXPORTED_SYMBOL #define Py_LOCAL_SYMBOL #endif + #define _PyINIT_EXPORTED_SYMBOL Py_EXPORTED_SYMBOL #endif /* only get special linkage if built as shared or platform is Cygwin */ #if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__) # if defined(HAVE_DECLSPEC_DLL) # if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -# define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE -# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE /* module init functions inside the core need no external linkage */ /* except for Cygwin to handle embedding */ -# if defined(__CYGWIN__) -# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL -# else /* __CYGWIN__ */ +# if !defined(__CYGWIN__) # define _PyINIT_FUNC_DECLSPEC # endif /* __CYGWIN__ */ # else /* Py_BUILD_CORE */ @@ -77,12 +80,6 @@ # define PyAPI_FUNC(RTYPE) Py_IMPORTED_SYMBOL RTYPE # endif /* !__CYGWIN__ */ # define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE - /* module init functions outside the core must be exported */ -# if defined(__cplusplus) -# define _PyINIT_FUNC_DECLSPEC extern "C" Py_EXPORTED_SYMBOL -# else /* __cplusplus */ -# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL -# endif /* __cplusplus */ # endif /* Py_BUILD_CORE */ # endif /* HAVE_DECLSPEC_DLL */ #endif /* Py_ENABLE_SHARED */ @@ -96,13 +93,17 @@ #endif #ifndef _PyINIT_FUNC_DECLSPEC # if defined(__cplusplus) -# define _PyINIT_FUNC_DECLSPEC extern "C" Py_EXPORTED_SYMBOL +# define _PyINIT_FUNC_DECLSPEC extern "C" _PyINIT_EXPORTED_SYMBOL # else /* __cplusplus */ -# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL +# define _PyINIT_FUNC_DECLSPEC _PyINIT_EXPORTED_SYMBOL # endif /* __cplusplus */ #endif -#define PyMODINIT_FUNC _PyINIT_FUNC_DECLSPEC PyObject* -#define PyMODEXPORT_FUNC _PyINIT_FUNC_DECLSPEC PyModuleDef_Slot* +#ifndef PyMODINIT_FUNC + #define PyMODINIT_FUNC _PyINIT_FUNC_DECLSPEC PyObject* +#endif +#ifndef PyMODEXPORT_FUNC + #define PyMODEXPORT_FUNC _PyINIT_FUNC_DECLSPEC PyModuleDef_Slot* +#endif #endif /* Py_EXPORTS_H */ diff --git a/Lib/pydoc.py b/Lib/pydoc.py index f3b44c9b3a620a..69c83e085113c9 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2004,10 +2004,11 @@ def interact(self): while True: try: request = self.getline('help> ') - if not request: break except (KeyboardInterrupt, EOFError): break request = request.strip() + if not request: + continue # back to the prompt # Make sure significant trailing quoting marks of literals don't # get deleted while cleaning input diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 655f5a9be7fa31..0d5c6e6e77f5d7 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -210,7 +210,7 @@ ctypes = None from test.support import (cpython_only, check_impl_detail, requires_debug_ranges, - gc_collect, Py_GIL_DISABLED) + gc_collect, Py_GIL_DISABLED, late_deletion) from test.support.script_helper import assert_python_ok from test.support import threading_helper, import_helper from test.support.bytecode_helper import instructions_with_positions @@ -1555,6 +1555,11 @@ def myfree(ptr): FREE_FUNC = freefunc(myfree) FREE_INDEX = RequestCodeExtraIndex(FREE_FUNC) + # Make sure myfree sticks around at least as long as the interpreter, + # since we (currently) can't unregister the function and leaving a + # dangling pointer will cause a crash on deallocation of code objects if + # something else uses co_extras, like test_capi.test_misc. + late_deletion(myfree) class CoExtra(unittest.TestCase): def get_func(self): diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 3e12a2a96fa381..0e113006cfa156 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -2147,10 +2147,47 @@ def test_url_requests(self): class TestHelper(unittest.TestCase): + def mock_interactive_session(self, inputs): + """ + Given a list of inputs, run an interactive help session. Returns a string + of what would be shown on screen. + """ + input_iter = iter(inputs) + + def mock_getline(prompt): + output.write(prompt) + next_input = next(input_iter) + output.write(next_input + os.linesep) + return next_input + + with captured_stdout() as output: + helper = pydoc.Helper(output=output) + with unittest.mock.patch.object(helper, "getline", mock_getline): + helper.interact() + + # handle different line endings across platforms consistently + return output.getvalue().strip().splitlines(keepends=False) + def test_keywords(self): self.assertEqual(sorted(pydoc.Helper.keywords), sorted(keyword.kwlist)) + def test_interact_empty_line_continues(self): + # gh-138568: test pressing Enter without input should continue in help session + self.assertEqual( + self.mock_interactive_session(["", " ", "quit"]), + ["help> ", "help> ", "help> quit"], + ) + + def test_interact_quit_commands_exit(self): + quit_commands = ["quit", "q", "exit"] + for quit_cmd in quit_commands: + with self.subTest(quit_command=quit_cmd): + self.assertEqual( + self.mock_interactive_session([quit_cmd]), + [f"help> {quit_cmd}"], + ) + class PydocWithMetaClasses(unittest.TestCase): def tearDown(self): diff --git a/Misc/NEWS.d/next/C_API/2025-11-17-17-46-16.gh-issue-141671.cVXNW5.rst b/Misc/NEWS.d/next/C_API/2025-11-17-17-46-16.gh-issue-141671.cVXNW5.rst new file mode 100644 index 00000000000000..304a6a5f75ff3b --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-11-17-17-46-16.gh-issue-141671.cVXNW5.rst @@ -0,0 +1,2 @@ +:c:macro:`PyMODINIT_FUNC` (and the new :c:macro:`PyMODEXPORT_FUNC`) now adds +a linkage declaration (``__declspec(dllexport)``) on Windows. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-06-08-29-08.gh-issue-138568.iZlalC.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-06-08-29-08.gh-issue-138568.iZlalC.rst new file mode 100644 index 00000000000000..8a916310259c78 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-06-08-29-08.gh-issue-138568.iZlalC.rst @@ -0,0 +1,2 @@ +Adjusted the built-in :func:`help` function so that empty inputs are ignored in +interactive mode.