Skip to content
Merged
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
9 changes: 6 additions & 3 deletions Doc/library/importlib.resources.abc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,14 @@
If the resource does not concretely exist on the file system,
raise :exc:`FileNotFoundError`.

.. method:: is_resource(name)
.. method:: is_resource(path)
:abstractmethod:

Returns ``True`` if the named *name* is considered a resource.
:exc:`FileNotFoundError` is raised if *name* does not exist.
Returns ``True`` if the named *path* is considered a resource.
:exc:`FileNotFoundError` is raised if *path* does not exist.

.. versionchanged:: 3.10
The argument *name* was renamed to *path*.

.. method:: contents()
:abstractmethod:
Expand Down
6 changes: 6 additions & 0 deletions Doc/library/test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,12 @@ The :mod:`test.support` module defines the following functions:
tests.


.. function:: get_resource_value(resource)

Return the value specified for *resource* (as :samp:`-u {resource}={value}`).
Return ``None`` if *resource* is disabled or no value is specified.


.. function:: python_is_optimized()

Return ``True`` if Python was not built with ``-O0`` or ``-Og``.
Expand Down
2 changes: 1 addition & 1 deletion Lib/copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def _reconstruct(x, memo, func, args,
*, deepcopy=deepcopy):
deep = memo is not None
if deep and args:
args = (deepcopy(arg, memo) for arg in args)
args = [deepcopy(arg, memo) for arg in args]
y = func(*args)
if deep:
memo[id(x)] = y
Expand Down
47 changes: 24 additions & 23 deletions Lib/test/libregrtest/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def __init__(self, **kwargs) -> None:
self.randomize = False
self.fromfile = None
self.fail_env_changed = False
self.use_resources: list[str] = []
self.use_resources: dict[str, str | None] = {}
self.trace = False
self.coverdir = 'coverage'
self.runleaks = False
Expand Down Expand Up @@ -309,7 +309,7 @@ def _create_parser():
group.add_argument('-G', '--failfast', action='store_true',
help='fail as soon as a test fails (only with -v or -W)')
group.add_argument('-u', '--use', metavar='RES1,RES2,...',
action='append', type=resources_list,
action='extend', type=resources_list,
help='specify which special resource intensive tests '
'to run.' + more_details)
group.add_argument('-M', '--memlimit', metavar='LIMIT',
Expand Down Expand Up @@ -414,11 +414,18 @@ def huntrleaks(string):


def resources_list(string):
u = [x.lower() for x in string.split(',')]
for r in u:
u = []
for x in string.split(','):
r, eq, v = x.partition('=')
r = r.lower()
u.append((r, v if eq else None))
if r == 'all' or r == 'none':
if eq:
raise argparse.ArgumentTypeError('invalid resource: ' + x)
continue
if r[0] == '-':
if eq:
raise argparse.ArgumentTypeError('invalid resource: ' + x)
r = r[1:]
if r not in RESOURCE_NAMES:
raise argparse.ArgumentTypeError('invalid resource: ' + r)
Expand Down Expand Up @@ -486,14 +493,14 @@ def _parse_args(args, **kwargs):
# Similar to: -u "all" --timeout=1200
if ns.use is None:
ns.use = []
ns.use.insert(0, ['all'])
ns.use[:0] = [('all', None)]
if ns.timeout is None:
ns.timeout = 1200 # 20 minutes
elif ns.fast_ci:
# Similar to: -u "all,-cpu" --timeout=600
if ns.use is None:
ns.use = []
ns.use.insert(0, ['all', '-cpu'])
ns.use[:0] = [('all', None), ('-cpu', None)]
if ns.timeout is None:
ns.timeout = 600 # 10 minutes

Expand Down Expand Up @@ -531,23 +538,17 @@ def _parse_args(args, **kwargs):
if ns.timeout <= 0:
ns.timeout = None
if ns.use:
for a in ns.use:
for r in a:
if r == 'all':
ns.use_resources[:] = ALL_RESOURCES
continue
if r == 'none':
del ns.use_resources[:]
continue
remove = False
if r[0] == '-':
remove = True
r = r[1:]
if remove:
if r in ns.use_resources:
ns.use_resources.remove(r)
elif r not in ns.use_resources:
ns.use_resources.append(r)
for r, v in ns.use:
if r == 'all':
for r in ALL_RESOURCES:
ns.use_resources[r] = None
elif r == 'none':
ns.use_resources.clear()
elif r[0] == '-':
r = r[1:]
ns.use_resources.pop(r, None)
else:
ns.use_resources[r] = v
if ns.random_seed is not None:
ns.randomize = True
if ns.no_randomize:
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/libregrtest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False):
self.junit_filename: StrPath | None = ns.xmlpath
self.memory_limit: str | None = ns.memlimit
self.gc_threshold: int | None = ns.threshold
self.use_resources: tuple[str, ...] = tuple(ns.use_resources)
self.use_resources: dict[str, str | None] = dict(ns.use_resources)
if ns.python:
self.python_cmd: tuple[str, ...] | None = tuple(ns.python)
else:
Expand Down
11 changes: 9 additions & 2 deletions Lib/test/libregrtest/runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class RunTests:
coverage: bool
memory_limit: str | None
gc_threshold: int | None
use_resources: tuple[str, ...]
use_resources: dict[str, str | None]
python_cmd: tuple[str, ...] | None
randomize: bool
random_seed: int | str
Expand Down Expand Up @@ -179,7 +179,14 @@ def bisect_cmd_args(self) -> list[str]:
if self.gc_threshold:
args.append(f"--threshold={self.gc_threshold}")
if self.use_resources:
args.extend(("-u", ','.join(self.use_resources)))
simple = ','.join(resource
for resource, value in self.use_resources.items()
if value is None)
if simple:
args.extend(("-u", simple))
for resource, value in self.use_resources.items():
if value is not None:
args.extend(("-u", f"{resource}={value}"))
if self.python_cmd:
cmd = shlex.join(self.python_cmd)
args.extend(("--python", cmd))
Expand Down
27 changes: 18 additions & 9 deletions Lib/test/libregrtest/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import sysconfig
import tempfile
import textwrap
from collections.abc import Callable, Iterable
from collections.abc import Callable

from test import support
from test.support import os_helper
Expand Down Expand Up @@ -607,21 +607,30 @@ def is_cross_compiled() -> bool:
return ('_PYTHON_HOST_PLATFORM' in os.environ)


def format_resources(use_resources: Iterable[str]) -> str:
use_resources = set(use_resources)
def format_resources(use_resources: dict[str, str | None]) -> str:
all_resources = set(ALL_RESOURCES)

values = []
for name in sorted(use_resources):
if use_resources[name] is not None:
values.append(f'{name}={use_resources[name]}')

# Express resources relative to "all"
relative_all = ['all']
for name in sorted(all_resources - use_resources):
for name in sorted(all_resources - set(use_resources)):
relative_all.append(f'-{name}')
for name in sorted(use_resources - all_resources):
relative_all.append(f'{name}')
all_text = ','.join(relative_all)
for name in sorted(set(use_resources) - all_resources):
if use_resources[name] is None:
relative_all.append(name)
all_text = ','.join(relative_all + values)
all_text = f"resources: {all_text}"

# List of enabled resources
text = ','.join(sorted(use_resources))
resources = []
for name in sorted(use_resources):
if use_resources[name] is None:
resources.append(name)
text = ','.join(resources + values)
text = f"resources ({len(use_resources)}): {text}"

# Pick the shortest string (prefer relative to all if lengths are equal)
Expand All @@ -631,7 +640,7 @@ def format_resources(use_resources: Iterable[str]) -> str:
return text


def display_header(use_resources: tuple[str, ...],
def display_header(use_resources: dict[str, str | None],
python_cmd: tuple[str, ...] | None) -> None:
# Print basic platform information
print("==", platform.python_implementation(), *sys.version.split())
Expand Down
15 changes: 13 additions & 2 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"record_original_stdout", "get_original_stdout", "captured_stdout",
"captured_stdin", "captured_stderr", "captured_output",
# unittest
"is_resource_enabled", "requires", "requires_freebsd_version",
"is_resource_enabled", "get_resource_value", "requires", "requires_resource",
"requires_freebsd_version",
"requires_gil_enabled", "requires_linux_version", "requires_mac_ver",
"check_syntax_error",
"requires_gzip", "requires_bz2", "requires_lzma", "requires_zstd",
Expand Down Expand Up @@ -185,7 +186,7 @@ def get_attribute(obj, name):
return attribute

verbose = 1 # Flag set to 0 by regrtest.py
use_resources = None # Flag set to [] by regrtest.py
use_resources = None # Flag set to {} by regrtest.py
max_memuse = 0 # Disable bigmem tests (they will still be run with
# small sizes, to make sure they work.)
real_max_memuse = 0
Expand Down Expand Up @@ -300,6 +301,16 @@ def is_resource_enabled(resource):
"""
return use_resources is None or resource in use_resources

def get_resource_value(resource):
"""Test whether a resource is enabled.

Known resources are set by regrtest.py. If not running under regrtest.py,
all resources are assumed enabled unless use_resources has been set.
"""
if use_resources is None:
return None
return use_resources.get(resource)

def requires(resource, msg=None):
"""Raise ResourceDenied if the specified resource is not available."""
if not is_resource_enabled(resource):
Expand Down
10 changes: 10 additions & 0 deletions Lib/test/test_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
# to ensure the Queue locks remain stable.
import itertools
import random
import struct
import threading
import time
import unittest
import weakref
from test.support import gc_collect, bigmemtest
from test.support import import_helper
from test.support import threading_helper
from test import support

# queue module depends on threading primitives
threading_helper.requires_working_threading(module=True)
Expand Down Expand Up @@ -1031,6 +1033,14 @@ def test_is_default(self):
self.assertIs(self.type2test, self.queue.SimpleQueue)
self.assertIs(self.type2test, self.queue.SimpleQueue)

def test_simplequeue_sizeof(self):
q = self.type2test()
basesize = support.calcobjsize('?nnPnnP')
support.check_sizeof(self, q, basesize + struct.calcsize(8 * 'P'))
for _ in range(1000):
q.put(object())
support.check_sizeof(self, q, basesize + struct.calcsize(1024 * 'P'))

def test_reentrancy(self):
# bpo-14976: put() may be called reentrantly in an asynchronous
# callback.
Expand Down
Loading
Loading