From 32aaaf9db3ffbe30a87c7b24a44902819f6968aa Mon Sep 17 00:00:00 2001 From: Adam Meily Date: Thu, 28 Mar 2024 10:50:18 -0400 Subject: [PATCH 1/8] allow __doc__ to be None for embedded Python installations --- src/trio/_path.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/trio/_path.py b/src/trio/_path.py index cb19008d54..55106e8d51 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -38,11 +38,10 @@ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: return await run_sync(partial(fn, *args, **kwargs)) update_wrapper(wrapper, wrapped) - assert wrapped.__doc__ is not None wrapper.__doc__ = ( f"Like :meth:`~{wrapped.__module__}.{wrapped.__qualname__}`, but async.\n" f"\n" - f"{cleandoc(wrapped.__doc__)}\n" + f"{cleandoc(wrapped.__doc__ or '')}\n" ) return wrapper @@ -76,7 +75,8 @@ def _wrap_method_path_iterable( def wrapper(self: PathT, /, *args: P.args, **kwargs: P.kwargs) -> Iterable[PathT]: return map(self.__class__, [*fn(self._wrapped_cls(self), *args, **kwargs)]) - assert wrapper.__doc__ is not None + if wrapper.__doc__ is None: + wrapper.__doc__ = "" wrapper.__doc__ += ( f"\n" f"This is an async method that returns a synchronous iterator, so you\n" From f2f88dbcab2427d3cc33330f6581f88ffcc4ca7d Mon Sep 17 00:00:00 2001 From: Adam Meily Date: Fri, 29 Mar 2024 20:36:23 -0400 Subject: [PATCH 2/8] minor change --- src/trio/_path.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/trio/_path.py b/src/trio/_path.py index 55106e8d51..d30a455746 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -75,9 +75,7 @@ def _wrap_method_path_iterable( def wrapper(self: PathT, /, *args: P.args, **kwargs: P.kwargs) -> Iterable[PathT]: return map(self.__class__, [*fn(self._wrapped_cls(self), *args, **kwargs)]) - if wrapper.__doc__ is None: - wrapper.__doc__ = "" - wrapper.__doc__ += ( + wrapper.__doc__ = (wrapper.__doc__ or "") + ( f"\n" f"This is an async method that returns a synchronous iterator, so you\n" f"use it like:\n" From 9eb81fbfd65c11467c53c9abd94f99955abe5b22 Mon Sep 17 00:00:00 2001 From: Adam Meily Date: Sat, 6 Apr 2024 20:27:14 -0400 Subject: [PATCH 3/8] address PR feedback --- src/trio/_path.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/trio/_path.py b/src/trio/_path.py index d30a455746..04f2e0b762 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -75,22 +75,23 @@ def _wrap_method_path_iterable( def wrapper(self: PathT, /, *args: P.args, **kwargs: P.kwargs) -> Iterable[PathT]: return map(self.__class__, [*fn(self._wrapped_cls(self), *args, **kwargs)]) - wrapper.__doc__ = (wrapper.__doc__ or "") + ( - f"\n" - f"This is an async method that returns a synchronous iterator, so you\n" - f"use it like:\n" - f"\n" - f".. code:: python\n" - f"\n" - f" for subpath in await mypath.{fn.__name__}():\n" - f" ...\n" - f"\n" - f".. note::\n" - f"\n" - f" The iterator is loaded into memory immediately during the initial\n" - f" call (see `issue #501\n" - f" `__ for discussion).\n" - ) + if wrapper.__doc__: + wrapper.__doc__ += ( + f"\n" + f"This is an async method that returns a synchronous iterator, so you\n" + f"use it like:\n" + f"\n" + f".. code:: python\n" + f"\n" + f" for subpath in await mypath.{fn.__name__}():\n" + f" ...\n" + f"\n" + f".. note::\n" + f"\n" + f" The iterator is loaded into memory immediately during the initial\n" + f" call (see `issue #501\n" + f" `__ for discussion).\n" + ) return wrapper From 28955dcc0d89ea5a11e1040ba2afa1e2f509a756 Mon Sep 17 00:00:00 2001 From: Adam Meily Date: Sat, 6 Apr 2024 21:32:57 -0400 Subject: [PATCH 4/8] address PR feedback --- src/trio/_path.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/trio/_path.py b/src/trio/_path.py index 04f2e0b762..907b0203f6 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -38,11 +38,12 @@ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: return await run_sync(partial(fn, *args, **kwargs)) update_wrapper(wrapper, wrapped) - wrapper.__doc__ = ( - f"Like :meth:`~{wrapped.__module__}.{wrapped.__qualname__}`, but async.\n" - f"\n" - f"{cleandoc(wrapped.__doc__ or '')}\n" - ) + if wrapped.__doc__: + wrapper.__doc__ = ( + f"Like :meth:`~{wrapped.__module__}.{wrapped.__qualname__}`, but async.\n" + f"\n" + f"{cleandoc(wrapped.__doc__)}\n" + ) return wrapper return decorator From a01e7af7a9b61eb051b52df579750d95e3dafb89 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Fri, 12 Apr 2024 15:31:26 +0900 Subject: [PATCH 5/8] Add in test case (cause it's annoying) --- src/trio/_tests/test_path.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/trio/_tests/test_path.py b/src/trio/_tests/test_path.py index 21ebefc90d..4df5a8ad84 100644 --- a/src/trio/_tests/test_path.py +++ b/src/trio/_tests/test_path.py @@ -252,3 +252,21 @@ async def test_classmethods() -> None: # Wrapped method has docstring assert trio.Path.home.__doc__ + + +@pytest.mark.parametrize( + "wrapper", + [ + trio._path._wraps_async, + trio._path._wrap_method, + trio._path._wrap_method_path, + trio._path._wrap_method_path_iterable, + ], +) +def test_wrapping_without_docstrings( + wrapper: Callable[[Callable[[], None]], Callable[[], None]] +) -> None: + @wrapper + def func_without_docstring() -> None: ... + + assert func_without_docstring.__doc__ is None From fefb995f571f7202a12ad5bfe1acbde90e86dfe4 Mon Sep 17 00:00:00 2001 From: John Litborn <11260241+jakkdl@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:49:38 +0200 Subject: [PATCH 6/8] Update src/trio/_tests/test_path.py --- src/trio/_tests/test_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_path.py b/src/trio/_tests/test_path.py index 4df5a8ad84..db7aebf2df 100644 --- a/src/trio/_tests/test_path.py +++ b/src/trio/_tests/test_path.py @@ -267,6 +267,6 @@ def test_wrapping_without_docstrings( wrapper: Callable[[Callable[[], None]], Callable[[], None]] ) -> None: @wrapper - def func_without_docstring() -> None: ... + def func_without_docstring() -> None: ... # pragma: no cover assert func_without_docstring.__doc__ is None From fb1f25c7bb271de50f2cfbc410a9d216b0a79454 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 15 Apr 2024 12:04:00 +0200 Subject: [PATCH 7/8] add newsfragment --- newsfragments/2987.issue.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/2987.issue.rst diff --git a/newsfragments/2987.issue.rst b/newsfragments/2987.issue.rst new file mode 100644 index 0000000000..8b542cf9db --- /dev/null +++ b/newsfragments/2987.issue.rst @@ -0,0 +1 @@ +Fix crash when importing trio in python windows embedded, and other installs that removes docstrings. From b5196458a3c8decca05aa42f34adabe92d2068d2 Mon Sep 17 00:00:00 2001 From: John Litborn <11260241+jakkdl@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:53:58 +0200 Subject: [PATCH 8/8] Update newsfragments/2987.issue.rst Co-authored-by: EXPLOSION --- newsfragments/2987.issue.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newsfragments/2987.issue.rst b/newsfragments/2987.issue.rst index 8b542cf9db..4c0adb1540 100644 --- a/newsfragments/2987.issue.rst +++ b/newsfragments/2987.issue.rst @@ -1 +1 @@ -Fix crash when importing trio in python windows embedded, and other installs that removes docstrings. +Fix crash when importing trio in embedded Python on Windows, and other installs that remove docstrings.