Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ updates:
# Cooldowns protect against supply chain attacks by avoiding the
# highest-risk window immediately after new releases.
default-days: 14
rebase-strategy: "auto"
- package-ecosystem: "pip"
directory: "/Tools/"
schedule:
Expand All @@ -26,3 +27,4 @@ updates:
- "skip news"
cooldown:
default-days: 14
rebase-strategy: "auto"
3 changes: 2 additions & 1 deletion Lib/test/libregrtest/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import sys
import sysconfig
import tempfile
import threading
import textwrap
from collections.abc import Callable

Expand Down Expand Up @@ -150,7 +151,7 @@ def setup_unraisable_hook() -> None:
sys.unraisablehook = regrtest_unraisable_hook


orig_threading_excepthook: Callable[..., None] | None = None
orig_threading_excepthook: Callable[[threading.ExceptHookArgs], None] | None = None


def regrtest_threading_excepthook(args) -> None:
Expand Down
67 changes: 52 additions & 15 deletions Lib/test/support/os_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,37 +512,74 @@ def temp_dir(path=None, quiet=False):
on error. Otherwise, if the path is specified and cannot be
created, only a warning is issued.

This function sanitizes non-ASCII and unsafe characters to prevent
Windows CI failures, and falls back to tempfile.mkdtemp() if creation fails.
"""
import tempfile

dir_created = False

# Sanitize the provided path to avoid invalid filesystem characters.
if path is not None:
try:
if not isinstance(path, str):
path = str(path)
# Replace non-ASCII characters with "_"
path = re.sub(r'[^\x00-\x7F]', '_', path)
# Replace unsafe filesystem characters
path = re.sub(r'[^A-Za-z0-9._\\/-]', '_', path)
# Prevent empty or broken names
if not path.strip():
path = None
except BaseException:
path = None

# If path is None or mkdir fails, use mkdtemp
if path is None:
path = tempfile.mkdtemp()
path = tempfile.mkdtemp(prefix="test_python_")
dir_created = True
path = os.path.realpath(path)
else:
try:
os.mkdir(path)
dir_created = True
except OSError as exc:
if not quiet:
raise
logging.getLogger(__name__).warning(
"tests may fail, unable to create temporary directory %r: %s",
path,
exc,
exc_info=exc,
stack_info=True,
stacklevel=3,
)
except OSError:
try:
path = tempfile.mkdtemp(prefix="test_python_")
dir_created = True
path = os.path.realpath(path)
except BaseException as exc:
if not quiet:
raise
logging.getLogger(__name__).warning(
"tests may fail, unable to create temporary directory %r: %s",
path,
exc,
exc_info=exc,
stack_info=True,
stacklevel=3,
)

if dir_created:
pid = os.getpid()

try:
yield path
finally:
# In case the process forks, let only the parent remove the
# directory. The child has a different process id. (bpo-30028)
# In case the process forks, only parent removes the directory
if dir_created and pid == os.getpid():
rmtree(path)
try:
from shutil import rmtree
rmtree(path)
except Exception as exc:
# Best-effort cleanup: ignore failures when removing the
# temporary directory, but log them for debugging purposes.
logging.getLogger(__name__).debug(
"Failed to remove temporary directory %r during cleanup: %s",
path,
exc,
exc_info=exc,
)


@contextlib.contextmanager
Expand Down
11 changes: 8 additions & 3 deletions Lib/test/test_tools/test_compute_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,18 @@ def test_ci_fuzz_stdlib(self):
with os_helper.change_cwd(basepath):
for p in LIBRARY_FUZZER_PATHS:
with self.subTest(p=p):
f = None
if p.is_dir():
f = p / "file"
candidate = p / "file"
if candidate.exists():
f = candidate
elif p.is_file():
f = p
if f is None:
continue
result = process_changed_files({f})
self.assertTrue(result.run_ci_fuzz_stdlib)
self.assertTrue(is_fuzzable_library_file(f))
self.assertTrue(result.run_ci_fuzz_stdlib, msg=f"CI fuzzing did not run for {f}")
self.assertTrue(is_fuzzable_library_file(f), msg=f"{f} should be recognized as fuzzable")

def test_android(self):
for d in ANDROID_DIRS:
Expand Down
4 changes: 4 additions & 0 deletions Tools/clinic/libclinic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
is_legal_c_identifier,
is_legal_py_identifier,
)
from . import cpp
from .utils import (
FormatCounterFormatter,
NULL,
Expand Down Expand Up @@ -61,6 +62,9 @@
"is_legal_c_identifier",
"is_legal_py_identifier",

# Submodules
"cpp",

# Utility functions
"FormatCounterFormatter",
"NULL",
Expand Down
Loading