Skip to content

Commit 02ac588

Browse files
committed
Merge remote-tracking branch 'origin/main' into fail_after_documentation
2 parents 6a7650d + b834f73 commit 02ac588

File tree

6 files changed

+77
-28
lines changed

6 files changed

+77
-28
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ repos:
2424
hooks:
2525
- id: black
2626
- repo: https://github.com/astral-sh/ruff-pre-commit
27-
rev: v0.6.4
27+
rev: v0.6.5
2828
hooks:
2929
- id: ruff
3030
types: [file]
@@ -35,7 +35,7 @@ repos:
3535
hooks:
3636
- id: codespell
3737
- repo: https://github.com/sphinx-contrib/sphinx-lint
38-
rev: v0.9.1
38+
rev: v1.0.0
3939
hooks:
4040
- id: sphinx-lint
4141
- repo: local

docs/source/conf.py

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
from __future__ import annotations
2020

2121
import collections.abc
22+
import glob
2223
import os
2324
import sys
2425
import types
26+
from pathlib import Path
2527
from typing import TYPE_CHECKING, cast
2628

2729
if TYPE_CHECKING:
@@ -36,19 +38,62 @@
3638
# Enable reloading with `typing.TYPE_CHECKING` being True
3739
os.environ["SPHINX_AUTODOC_RELOAD_MODULES"] = "1"
3840

39-
# https://docs.readthedocs.io/en/stable/builds.html#build-environment
40-
if "READTHEDOCS" in os.environ:
41-
import glob
42-
43-
if glob.glob("../../newsfragments/*.*.rst"):
44-
print("-- Found newsfragments; running towncrier --", flush=True)
45-
import subprocess
46-
41+
# Handle writing newsfragments into the history file.
42+
# We want to keep files unchanged when testing locally.
43+
# So immediately revert the contents after running towncrier,
44+
# then substitute when Sphinx wants to read it in.
45+
history_file = Path("history.rst")
46+
47+
history_new: str | None
48+
if glob.glob("../../newsfragments/*.*.rst"):
49+
print("-- Found newsfragments; running towncrier --", flush=True)
50+
history_orig = history_file.read_bytes()
51+
import subprocess
52+
53+
# In case changes were staged, preserve indexed version.
54+
# This grabs the hash of the current staged version.
55+
history_staged = subprocess.run(
56+
["git", "rev-parse", "--verify", ":docs/source/history.rst"],
57+
check=True,
58+
cwd="../..",
59+
stdout=subprocess.PIPE,
60+
encoding="ascii",
61+
).stdout.strip()
62+
try:
4763
subprocess.run(
48-
["towncrier", "--yes", "--date", "not released yet"],
64+
["towncrier", "--keep", "--date", "not released yet"],
4965
cwd="../..",
5066
check=True,
5167
)
68+
history_new = history_file.read_text("utf8")
69+
finally:
70+
# Make sure this reverts even if a failure occurred.
71+
# Restore whatever was staged.
72+
print(f"Restoring history.rst = {history_staged}")
73+
subprocess.run(
74+
[
75+
"git",
76+
"update-index",
77+
"--cacheinfo",
78+
f"100644,{history_staged},docs/source/history.rst",
79+
],
80+
cwd="../..",
81+
check=False,
82+
)
83+
# And restore the working copy.
84+
history_file.write_bytes(history_orig)
85+
del history_orig # We don't need this any more.
86+
else:
87+
# Leave it as is.
88+
history_new = None
89+
90+
91+
def on_read_source(app: Sphinx, docname: str, content: list[str]) -> None:
92+
"""Substitute the modified history file."""
93+
if docname == "history" and history_new is not None:
94+
# This is a 1-item list with the file contents.
95+
content[0] = history_new
96+
5297

5398
# Sphinx is very finicky, and somewhat buggy, so we have several different
5499
# methods to help it resolve links.
@@ -153,6 +198,7 @@ def setup(app: Sphinx) -> None:
153198
app.connect("autodoc-process-signature", autodoc_process_signature)
154199
# After Intersphinx runs, add additional mappings.
155200
app.connect("builder-inited", add_intersphinx, priority=1000)
201+
app.connect("source-read", on_read_source)
156202

157203

158204
# -- General configuration ------------------------------------------------

docs/source/history.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ Trio 0.23.2 (2023-12-14)
141141
Features
142142
~~~~~~~~
143143

144-
- `TypeVarTuple <https://docs.python.org/3.12/library/typing.html#typing.TypeVarTuple>`_ is now used to fully type :meth:`nursery.start_soon() <trio.Nursery.start_soon>`, :func:`trio.run()`, :func:`trio.to_thread.run_sync()`, and other similar functions accepting ``(func, *args)``. This means type checkers will be able to verify types are used correctly. :meth:`nursery.start() <trio.Nursery.start>` is not fully typed yet however. (`#2881 <https://github.com/python-trio/trio/issues/2881>`__)
144+
- `TypeVarTuple <https://docs.python.org/3.12/library/typing.html#typing.TypeVarTuple>`_ is now used to fully type :meth:`nursery.start_soon() <trio.Nursery.start_soon>`, :func:`trio.run`, :func:`trio.to_thread.run_sync`, and other similar functions accepting ``(func, *args)``. This means type checkers will be able to verify types are used correctly. :meth:`nursery.start() <trio.Nursery.start>` is not fully typed yet however. (`#2881 <https://github.com/python-trio/trio/issues/2881>`__)
145145

146146

147147
Bugfixes
@@ -1000,7 +1000,7 @@ Bugfixes
10001000
- Fixed a race condition on macOS, where Trio's TCP listener would crash if an
10011001
incoming TCP connection was closed before the listener had a chance to accept
10021002
it. (`#609 <https://github.com/python-trio/trio/issues/609>`__)
1003-
- :func:`trio.open_tcp_stream()` has been refactored to clean up unsuccessful
1003+
- :func:`trio.open_tcp_stream` has been refactored to clean up unsuccessful
10041004
connection attempts more reliably. (`#809
10051005
<https://github.com/python-trio/trio/issues/809>`__)
10061006

newsfragments/3076.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Update ``trio.lowlevel.open_process``'s documentation to allow bytes.

src/trio/_subprocess.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def kill(self) -> None:
304304

305305

306306
async def _open_process(
307-
command: list[str] | str,
307+
command: StrOrBytesPath | Sequence[StrOrBytesPath],
308308
*,
309309
stdin: int | HasFileno | None = None,
310310
stdout: int | HasFileno | None = None,
@@ -329,13 +329,14 @@ async def _open_process(
329329
want.
330330
331331
Args:
332-
command (list or str): The command to run. Typically this is a
333-
sequence of strings such as ``['ls', '-l', 'directory with spaces']``,
334-
where the first element names the executable to invoke and the other
335-
elements specify its arguments. With ``shell=True`` in the
336-
``**options``, or on Windows, ``command`` may alternatively
337-
be a string, which will be parsed following platform-dependent
338-
:ref:`quoting rules <subprocess-quoting>`.
332+
command: The command to run. Typically this is a sequence of strings or
333+
bytes such as ``['ls', '-l', 'directory with spaces']``, where the
334+
first element names the executable to invoke and the other elements
335+
specify its arguments. With ``shell=True`` in the ``**options``, or on
336+
Windows, ``command`` can be a string or bytes, which will be parsed
337+
following platform-dependent :ref:`quoting rules
338+
<subprocess-quoting>`. In all cases ``command`` can be a path or a
339+
sequence of paths.
339340
stdin: Specifies what the child process's standard input
340341
stream should connect to: output written by the parent
341342
(``subprocess.PIPE``), nothing (``subprocess.DEVNULL``),
@@ -369,15 +370,16 @@ async def _open_process(
369370
)
370371

371372
if os.name == "posix":
372-
if isinstance(command, str) and not options.get("shell"):
373+
# TODO: how do paths and sequences thereof play with `shell=True`?
374+
if isinstance(command, (str, bytes)) and not options.get("shell"):
373375
raise TypeError(
374-
"command must be a sequence (not a string) if shell=False "
375-
"on UNIX systems",
376+
"command must be a sequence (not a string or bytes) if "
377+
"shell=False on UNIX systems",
376378
)
377-
if not isinstance(command, str) and options.get("shell"):
379+
if not isinstance(command, (str, bytes)) and options.get("shell"):
378380
raise TypeError(
379-
"command must be a string (not a sequence) if shell=True "
380-
"on UNIX systems",
381+
"command must be a string or bytes (not a sequence) if "
382+
"shell=True on UNIX systems",
381383
)
382384

383385
trio_stdin: ClosableSendStream | None = None

src/trio/_tools/gen_exports.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def process(files: Iterable[File], *, do_test: bool) -> None:
303303
print("Generated sources are up to date.")
304304
else:
305305
for new_path, new_source in new_files.items():
306-
with open(new_path, "w", encoding="utf-8") as f:
306+
with open(new_path, "w", encoding="utf-8", newline="\n") as f:
307307
f.write(new_source)
308308
print("Regenerated sources successfully.")
309309
if not matches_disk:

0 commit comments

Comments
 (0)