Skip to content

Commit a8466ff

Browse files
authored
Merge branch 'main' into fix-issue-134833
2 parents ba93308 + e64395e commit a8466ff

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1727
-336
lines changed

Doc/c-api/init_config.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2111,7 +2111,7 @@ initialization::
21112111
21122112
/* Specify sys.path explicitly */
21132113
/* If you want to modify the default set of paths, finish
2114-
initialization first and then use PySys_GetObject("path") */
2114+
initialization first and then use PySys_GetAttrString("path") */
21152115
config.module_search_paths_set = 1;
21162116
status = PyWideStringList_Append(&config.module_search_paths,
21172117
L"/path/to/stdlib");

Doc/c-api/sys.rst

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,57 @@ These are utility functions that make functionality from the :mod:`sys` module
258258
accessible to C code. They all work with the current interpreter thread's
259259
:mod:`sys` module's dict, which is contained in the internal thread state structure.
260260
261+
.. c:function:: PyObject *PySys_GetAttr(PyObject *name)
262+
263+
Get the attribute *name* of the :mod:`sys` module.
264+
Return a :term:`strong reference`.
265+
Raise :exc:`RuntimeError` and return ``NULL`` if it does not exist or
266+
if the :mod:`sys` module cannot be found.
267+
268+
If the non-existing object should not be treated as a failure, you can use
269+
:c:func:`PySys_GetOptionalAttr` instead.
270+
271+
.. versionadded:: next
272+
273+
.. c:function:: PyObject *PySys_GetAttrString(const char *name)
274+
275+
This is the same as :c:func:`PySys_GetAttr`, but *name* is
276+
specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
277+
rather than a :c:expr:`PyObject*`.
278+
279+
If the non-existing object should not be treated as a failure, you can use
280+
:c:func:`PySys_GetOptionalAttrString` instead.
281+
282+
.. versionadded:: next
283+
284+
.. c:function:: int PySys_GetOptionalAttr(PyObject *name, PyObject **result)
285+
286+
Variant of :c:func:`PySys_GetAttr` which doesn't raise
287+
exception if the object does not exist.
288+
289+
* Set *\*result* to a new :term:`strong reference` to the object and
290+
return ``1`` if the object exists.
291+
* Set *\*result* to ``NULL`` and return ``0`` without setting an exception
292+
if the object does not exist.
293+
* Set an exception, set *\*result* to ``NULL``, and return ``-1``,
294+
if an error occurred.
295+
296+
.. versionadded:: next
297+
298+
.. c:function:: int PySys_GetOptionalAttrString(const char *name, PyObject **result)
299+
300+
This is the same as :c:func:`PySys_GetOptionalAttr`, but *name* is
301+
specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
302+
rather than a :c:expr:`PyObject*`.
303+
304+
.. versionadded:: next
305+
261306
.. c:function:: PyObject *PySys_GetObject(const char *name)
262307
263-
Return the object *name* from the :mod:`sys` module or ``NULL`` if it does
264-
not exist, without setting an exception.
308+
Similar to :c:func:`PySys_GetAttrString`, but return a :term:`borrowed
309+
reference` and return ``NULL`` *without* setting exception on failure.
310+
311+
Preserves exception that was set before the call.
265312
266313
.. c:function:: int PySys_SetObject(const char *name, PyObject *v)
267314

Doc/data/stable_abi.dat

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/tools/extensions/audit_events.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from sphinx.util.docutils import SphinxDirective
1414

1515
if TYPE_CHECKING:
16-
from collections.abc import Iterator
16+
from collections.abc import Iterator, Set
1717

1818
from sphinx.application import Sphinx
1919
from sphinx.builders import Builder
@@ -33,7 +33,7 @@
3333
class AuditEvents:
3434
def __init__(self) -> None:
3535
self.events: dict[str, list[str]] = {}
36-
self.sources: dict[str, list[tuple[str, str]]] = {}
36+
self.sources: dict[str, set[tuple[str, str]]] = {}
3737

3838
def __iter__(self) -> Iterator[tuple[str, list[str], tuple[str, str]]]:
3939
for name, args in self.events.items():
@@ -47,7 +47,7 @@ def add_event(
4747
self._check_args_match(name, args)
4848
else:
4949
self.events[name] = args
50-
self.sources.setdefault(name, []).append(source)
50+
self.sources.setdefault(name, set()).add(source)
5151

5252
def _check_args_match(self, name: str, args: list[str]) -> None:
5353
current_args = self.events[name]
@@ -69,11 +69,11 @@ def _check_args_match(self, name: str, args: list[str]) -> None:
6969
return
7070

7171
def id_for(self, name) -> str:
72-
source_count = len(self.sources.get(name, ()))
72+
source_count = len(self.sources.get(name, set()))
7373
name_clean = re.sub(r"\W", "_", name)
7474
return f"audit_event_{name_clean}_{source_count}"
7575

76-
def rows(self) -> Iterator[tuple[str, list[str], list[tuple[str, str]]]]:
76+
def rows(self) -> Iterator[tuple[str, list[str], Set[tuple[str, str]]]]:
7777
for name in sorted(self.events.keys()):
7878
yield name, self.events[name], self.sources[name]
7979

@@ -218,7 +218,7 @@ def _make_row(
218218
docname: str,
219219
name: str,
220220
args: list[str],
221-
sources: list[tuple[str, str]],
221+
sources: Set[tuple[str, str]],
222222
) -> nodes.row:
223223
row = nodes.row()
224224
name_node = nodes.paragraph("", nodes.Text(name))
@@ -233,7 +233,7 @@ def _make_row(
233233
row += nodes.entry("", args_node)
234234

235235
backlinks_node = nodes.paragraph()
236-
backlinks = enumerate(sorted(set(sources)), start=1)
236+
backlinks = enumerate(sorted(sources), start=1)
237237
for i, (doc, label) in backlinks:
238238
if isinstance(label, str):
239239
ref = nodes.reference("", f"[{i}]", internal=True)
@@ -258,7 +258,7 @@ def setup(app: Sphinx):
258258
app.connect("env-purge-doc", audit_events_purge)
259259
app.connect("env-merge-info", audit_events_merge)
260260
return {
261-
"version": "1.0",
261+
"version": "2.0",
262262
"parallel_read_safe": True,
263263
"parallel_write_safe": True,
264264
}

Doc/whatsnew/3.15.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,10 @@ C API changes
213213
New features
214214
------------
215215

216-
* TODO
216+
* Add :c:func:`PySys_GetAttr`, :c:func:`PySys_GetAttrString`,
217+
:c:func:`PySys_GetOptionalAttr`, and :c:func:`PySys_GetOptionalAttrString`
218+
functions as replacements for :c:func:`PySys_GetObject`.
219+
(Contributed by Serhiy Storchaka in :gh:`108512`.)
217220

218221
Porting to Python 3.15
219222
----------------------

Include/internal/pycore_object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,8 @@ enum _PyAnnotateFormat {
10101010
_Py_ANNOTATE_FORMAT_STRING = 4,
10111011
};
10121012

1013+
int _PyObject_SetDict(PyObject *obj, PyObject *value);
1014+
10131015
#ifdef __cplusplus
10141016
}
10151017
#endif

Include/internal/pycore_sysmodule.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
PyAPI_FUNC(int) _PySys_GetOptionalAttr(PyObject *, PyObject **);
12-
PyAPI_FUNC(int) _PySys_GetOptionalAttrString(const char *, PyObject **);
13-
PyAPI_FUNC(PyObject *) _PySys_GetRequiredAttr(PyObject *);
14-
PyAPI_FUNC(PyObject *) _PySys_GetRequiredAttrString(const char *);
15-
1611
// Export for '_pickle' shared extension
1712
PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *);
1813

Include/pymacro.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,13 @@
231231
// "comparison of unsigned expression in '< 0' is always false".
232232
#define _Py_IS_TYPE_SIGNED(type) ((type)(-1) <= 0)
233233

234-
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030E0000 // 3.14
235234
// Version helpers. These are primarily macros, but have exported equivalents.
235+
#define _Py_PACK_VERSION(X, Y) _Py_PACK_FULL_VERSION(X, Y, 0, 0, 0)
236+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 14)
236237
PyAPI_FUNC(uint32_t) Py_PACK_FULL_VERSION(int x, int y, int z, int level, int serial);
237238
PyAPI_FUNC(uint32_t) Py_PACK_VERSION(int x, int y);
238239
#define Py_PACK_FULL_VERSION _Py_PACK_FULL_VERSION
239-
#define Py_PACK_VERSION(X, Y) Py_PACK_FULL_VERSION(X, Y, 0, 0, 0)
240+
#define Py_PACK_VERSION _Py_PACK_VERSION
240241
#endif // Py_LIMITED_API < 3.14
241242

242243

Include/sysmodule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
extern "C" {
55
#endif
66

7+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030f0000
8+
PyAPI_FUNC(PyObject *) PySys_GetAttr(PyObject *);
9+
PyAPI_FUNC(PyObject *) PySys_GetAttrString(const char *);
10+
PyAPI_FUNC(int) PySys_GetOptionalAttr(PyObject *, PyObject **);
11+
PyAPI_FUNC(int) PySys_GetOptionalAttrString(const char *, PyObject **);
12+
#endif
713
PyAPI_FUNC(PyObject *) PySys_GetObject(const char *);
814
PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *);
915

Lib/compression/zstd/_zstdfile.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import io
22
from os import PathLike
3-
from _zstd import (ZstdCompressor, ZstdDecompressor, ZstdError,
4-
ZSTD_DStreamOutSize)
3+
from _zstd import ZstdCompressor, ZstdDecompressor, ZSTD_DStreamOutSize
54
from compression._common import _streams
65

76
__all__ = ('ZstdFile', 'open')

0 commit comments

Comments
 (0)