Thread View
j: Next unread message
k: Previous unread message
j a: Jump to all threads
j l: Jump to MailingList overview
https://github.com/python/cpython/commit/7fcba2e3a9747d4b8bbe5a2fea2b66f671…
commit: 7fcba2e3a9747d4b8bbe5a2fea2b66f671130157
branch: 3.12
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: hugovk <1324225+hugovk(a)users.noreply.github.com>
date: 2024-12-31T21:31:21Z
summary:
[3.12] Reword `about.rst` to not limit Sphinx (GH-128325) (#128383)
Reword `about.rst` to not limit Sphinx (GH-128325)
(cherry picked from commit c5438fdf4706a70bdd19338edc000dacffff6837)
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland(a)users.noreply.github.com>
Co-authored-by: Adam Turner <9087854+AA-Turner(a)users.noreply.github.com>
files:
M Doc/about.rst
diff --git a/Doc/about.rst b/Doc/about.rst
index 5e6160ff2700ed..8f635d7f743a98 100644
--- a/Doc/about.rst
+++ b/Doc/about.rst
@@ -1,10 +1,11 @@
-=====================
-About these documents
-=====================
+========================
+About this documentation
+========================
-These documents are generated from `reStructuredText`_ sources by `Sphinx`_, a
-document processor specifically written for the Python documentation.
+Python's documentation is generated from `reStructuredText`_ sources
+using `Sphinx`_, a documentation generator originally created for Python
+and now maintained as an independent project.
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
.. _Sphinx: https://www.sphinx-doc.org/
@@ -20,14 +21,14 @@ volunteers are always welcome!
Many thanks go to:
* Fred L. Drake, Jr., the creator of the original Python documentation toolset
- and writer of much of the content;
+ and author of much of the content;
* the `Docutils <https://docutils.sourceforge.io/ >`_ project for creating
reStructuredText and the Docutils suite;
* Fredrik Lundh for his Alternative Python Reference project from which Sphinx
got many good ideas.
-Contributors to the Python Documentation
+Contributors to the Python documentation
----------------------------------------
Many people have contributed to the Python language, the Python standard
https://github.com/python/cpython/commit/675b039e46fae6f6b83c143fe4e5ba5bee…
commit: 675b039e46fae6f6b83c143fe4e5ba5bee3067dc
branch: 3.13
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: hugovk <1324225+hugovk(a)users.noreply.github.com>
date: 2024-12-31T21:28:59Z
summary:
[3.13] Reword `about.rst` to not limit Sphinx (GH-128325) (#128382)
Reword `about.rst` to not limit Sphinx (GH-128325)
(cherry picked from commit c5438fdf4706a70bdd19338edc000dacffff6837)
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland(a)users.noreply.github.com>
Co-authored-by: Adam Turner <9087854+AA-Turner(a)users.noreply.github.com>
files:
M Doc/about.rst
diff --git a/Doc/about.rst b/Doc/about.rst
index 5e6160ff2700ed..8f635d7f743a98 100644
--- a/Doc/about.rst
+++ b/Doc/about.rst
@@ -1,10 +1,11 @@
-=====================
-About these documents
-=====================
+========================
+About this documentation
+========================
-These documents are generated from `reStructuredText`_ sources by `Sphinx`_, a
-document processor specifically written for the Python documentation.
+Python's documentation is generated from `reStructuredText`_ sources
+using `Sphinx`_, a documentation generator originally created for Python
+and now maintained as an independent project.
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
.. _Sphinx: https://www.sphinx-doc.org/
@@ -20,14 +21,14 @@ volunteers are always welcome!
Many thanks go to:
* Fred L. Drake, Jr., the creator of the original Python documentation toolset
- and writer of much of the content;
+ and author of much of the content;
* the `Docutils <https://docutils.sourceforge.io/ >`_ project for creating
reStructuredText and the Docutils suite;
* Fredrik Lundh for his Alternative Python Reference project from which Sphinx
got many good ideas.
-Contributors to the Python Documentation
+Contributors to the Python documentation
----------------------------------------
Many people have contributed to the Python language, the Python standard
https://github.com/python/cpython/commit/c5438fdf4706a70bdd19338edc000dacff…
commit: c5438fdf4706a70bdd19338edc000dacffff6837
branch: main
author: Stan Ulbrych <89152624+StanFromIreland(a)users.noreply.github.com>
committer: hugovk <1324225+hugovk(a)users.noreply.github.com>
date: 2024-12-31T23:22:33+02:00
summary:
Reword `about.rst` to not limit Sphinx (#128325)
Co-authored-by: Adam Turner <9087854+AA-Turner(a)users.noreply.github.com>
files:
M Doc/about.rst
diff --git a/Doc/about.rst b/Doc/about.rst
index 5e6160ff2700ed..8f635d7f743a98 100644
--- a/Doc/about.rst
+++ b/Doc/about.rst
@@ -1,10 +1,11 @@
-=====================
-About these documents
-=====================
+========================
+About this documentation
+========================
-These documents are generated from `reStructuredText`_ sources by `Sphinx`_, a
-document processor specifically written for the Python documentation.
+Python's documentation is generated from `reStructuredText`_ sources
+using `Sphinx`_, a documentation generator originally created for Python
+and now maintained as an independent project.
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
.. _Sphinx: https://www.sphinx-doc.org/
@@ -20,14 +21,14 @@ volunteers are always welcome!
Many thanks go to:
* Fred L. Drake, Jr., the creator of the original Python documentation toolset
- and writer of much of the content;
+ and author of much of the content;
* the `Docutils <https://docutils.sourceforge.io/ >`_ project for creating
reStructuredText and the Docutils suite;
* Fredrik Lundh for his Alternative Python Reference project from which Sphinx
got many good ideas.
-Contributors to the Python Documentation
+Contributors to the Python documentation
----------------------------------------
Many people have contributed to the Python language, the Python standard
https://github.com/python/cpython/commit/08ae06fe46a0fef25432123aacd57a4289…
commit: 08ae06fe46a0fef25432123aacd57a4289335fc0
branch: 3.13
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2024-12-31T18:45:03Z
summary:
[3.13] gh-88834: Unify the instance check for typing.Union and types.UnionType (GH-128363) (GH-128370)
Union now uses the instance checks against its parameters instead of
the subclass checks.
(cherry picked from commit b2ac70a62ad1be8e037ce45ccf5f1b753ea5e64b)
Co-authored-by: Serhiy Storchaka <storchaka(a)gmail.com>
files:
A Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
M Lib/test/test_typing.py
M Lib/typing.py
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 06a37c5494db5c..6375d359e72ac8 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -120,7 +120,7 @@ class Sub(Any): pass
def test_errors(self):
with self.assertRaises(TypeError):
- issubclass(42, Any)
+ isinstance(42, Any)
with self.assertRaises(TypeError):
Any[int] # Any is not a generic type.
@@ -135,6 +135,9 @@ class Something: pass
class MockSomething(Something, Mock): pass
self.assertTrue(issubclass(MockSomething, Any))
+ self.assertTrue(issubclass(MockSomething, MockSomething))
+ self.assertTrue(issubclass(MockSomething, Something))
+ self.assertTrue(issubclass(MockSomething, Mock))
ms = MockSomething()
self.assertIsInstance(ms, MockSomething)
self.assertIsInstance(ms, Something)
@@ -2008,13 +2011,81 @@ def test_basics(self):
u = Union[int, float]
self.assertNotEqual(u, Union)
- def test_subclass_error(self):
+ def test_union_isinstance(self):
+ self.assertTrue(isinstance(42, Union[int, str]))
+ self.assertTrue(isinstance('abc', Union[int, str]))
+ self.assertFalse(isinstance(3.14, Union[int, str]))
+ self.assertTrue(isinstance(42, Union[int, list[int]]))
+ self.assertTrue(isinstance(42, Union[int, Any]))
+
+ def test_union_isinstance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[str, list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[list[int], int])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[list[int], str])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[str, Any])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[Any, int])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[Any, str])
+
+ def test_optional_isinstance(self):
+ self.assertTrue(isinstance(42, Optional[int]))
+ self.assertTrue(isinstance(None, Optional[int]))
+ self.assertFalse(isinstance('abc', Optional[int]))
+
+ def test_optional_isinstance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Optional[list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(None, Optional[list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(42, Optional[Any])
+ with self.assertRaises(TypeError):
+ isinstance(None, Optional[Any])
+
+ def test_union_issubclass(self):
+ self.assertTrue(issubclass(int, Union[int, str]))
+ self.assertTrue(issubclass(str, Union[int, str]))
+ self.assertFalse(issubclass(float, Union[int, str]))
+ self.assertTrue(issubclass(int, Union[int, list[int]]))
+ self.assertTrue(issubclass(int, Union[int, Any]))
+ self.assertFalse(issubclass(int, Union[str, Any]))
+ self.assertTrue(issubclass(int, Union[Any, int]))
+ self.assertFalse(issubclass(int, Union[Any, str]))
+
+ def test_union_issubclass_type_error(self):
with self.assertRaises(TypeError):
issubclass(int, Union)
with self.assertRaises(TypeError):
issubclass(Union, int)
with self.assertRaises(TypeError):
issubclass(Union[int, str], int)
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[str, list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[list[int], int])
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[list[int], str])
+
+ def test_optional_issubclass(self):
+ self.assertTrue(issubclass(int, Optional[int]))
+ self.assertTrue(issubclass(type(None), Optional[int]))
+ self.assertFalse(issubclass(str, Optional[int]))
+ self.assertTrue(issubclass(Any, Optional[Any]))
+ self.assertTrue(issubclass(type(None), Optional[Any]))
+ self.assertFalse(issubclass(int, Optional[Any]))
+
+ def test_optional_issubclass_type_error(self):
+ with self.assertRaises(TypeError):
+ issubclass(list[int], Optional[list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(type(None), Optional[list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(int, Optional[list[int]])
def test_union_any(self):
u = Union[Any]
diff --git a/Lib/typing.py b/Lib/typing.py
index bba29db8559da2..fe939a2e68b9bd 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1783,12 +1783,16 @@ def __repr__(self):
return super().__repr__()
def __instancecheck__(self, obj):
- return self.__subclasscheck__(type(obj))
+ for arg in self.__args__:
+ if isinstance(obj, arg):
+ return True
+ return False
def __subclasscheck__(self, cls):
for arg in self.__args__:
if issubclass(cls, arg):
return True
+ return False
def __reduce__(self):
func, (origin, args) = super().__reduce__()
diff --git a/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst b/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
new file mode 100644
index 00000000000000..ca43f914880ba3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
@@ -0,0 +1,3 @@
+Unify the instance check for :class:`typing.Union` and
+:class:`types.UnionType`: :class:`!Union` now uses the instance checks
+against its parameters instead of the subclass checks.
https://github.com/python/cpython/commit/e389d6c650ddacb55b08b657f1e4e9b133…
commit: e389d6c650ddacb55b08b657f1e4e9b1330f3455
branch: main
author: Kumar Aditya <kumaraditya(a)python.org>
committer: kumaraditya303 <kumaraditya(a)python.org>
date: 2024-12-31T19:10:06+05:30
summary:
gh-128277: make globals variables thread safe in socket module (#128286)
files:
M Modules/socketmodule.c
M Python/fileutils.c
M Tools/c-analyzer/cpython/globals-to-fix.tsv
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 1f0cbf6abb184c..efc8be3ab592ba 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -550,20 +550,20 @@ typedef struct _socket_state {
/* Default timeout for new sockets */
PyTime_t defaulttimeout;
+} socket_state;
#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
- int accept4_works;
+/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
+static int accept4_works = -1;
#endif
#endif
#ifdef SOCK_CLOEXEC
- /* socket() and socketpair() fail with EINVAL on Linux kernel older
- * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */
- int sock_cloexec_works;
+/* socket() and socketpair() fail with EINVAL on Linux kernel older
+ * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */
+static int sock_cloexec_works = -1;
#endif
-} socket_state;
static inline void
set_sock_fd(PySocketSockObject *s, SOCKET_T fd)
@@ -2904,16 +2904,15 @@ sock_accept_impl(PySocketSockObject *s, void *data)
#endif
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- socket_state *state = s->state;
- if (state->accept4_works != 0) {
+ if (_Py_atomic_load_int_relaxed(&accept4_works) != 0) {
ctx->result = accept4(get_sock_fd(s), addr, paddrlen,
SOCK_CLOEXEC);
- if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) {
+ if (ctx->result == INVALID_SOCKET && _Py_atomic_load_int_relaxed(&accept4_works) == -1) {
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
- state->accept4_works = (errno != ENOSYS);
+ _Py_atomic_store_int_relaxed(&accept4_works, errno != ENOSYS);
}
}
- if (state->accept4_works == 0)
+ if (_Py_atomic_load_int_relaxed(&accept4_works) == 0)
ctx->result = accept(get_sock_fd(s), addr, paddrlen);
#else
ctx->result = accept(get_sock_fd(s), addr, paddrlen);
@@ -2966,8 +2965,7 @@ sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
#else
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- socket_state *state = s->state;
- if (!state->accept4_works)
+ if (!_Py_atomic_load_int_relaxed(&accept4_works))
#endif
{
if (_Py_set_inheritable(newfd, 0, NULL) < 0) {
@@ -5428,7 +5426,7 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
#ifndef MS_WINDOWS
#ifdef SOCK_CLOEXEC
- int *atomic_flag_works = &state->sock_cloexec_works;
+ int *atomic_flag_works = &sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
@@ -5583,15 +5581,16 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
/* UNIX */
Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
- if (state->sock_cloexec_works != 0) {
+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) != 0) {
fd = socket(family, type | SOCK_CLOEXEC, proto);
- if (state->sock_cloexec_works == -1) {
+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) == -1) {
if (fd >= 0) {
- state->sock_cloexec_works = 1;
+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 1);
}
+
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
- state->sock_cloexec_works = 0;
+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 0);
fd = socket(family, type, proto);
}
}
@@ -6332,7 +6331,7 @@ socket_socketpair(PyObject *self, PyObject *args)
PyObject *res = NULL;
socket_state *state = get_module_state(self);
#ifdef SOCK_CLOEXEC
- int *atomic_flag_works = &state->sock_cloexec_works;
+ int *atomic_flag_works = &sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
@@ -6350,15 +6349,15 @@ socket_socketpair(PyObject *self, PyObject *args)
/* Create a pair of socket fds */
Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
- if (state->sock_cloexec_works != 0) {
+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) != 0) {
ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv);
- if (state->sock_cloexec_works == -1) {
+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) == -1) {
if (ret >= 0) {
- state->sock_cloexec_works = 1;
+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 1);
}
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
- state->sock_cloexec_works = 0;
+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 0);
ret = socketpair(family, type, proto, sv);
}
}
@@ -7466,17 +7465,8 @@ socket_exec(PyObject *m)
}
socket_state *state = get_module_state(m);
- state->defaulttimeout = _PYTIME_FROMSECONDS(-1);
-
-#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
-#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- state->accept4_works = -1;
-#endif
-#endif
-#ifdef SOCK_CLOEXEC
- state->sock_cloexec_works = -1;
-#endif
+ _Py_atomic_store_int64_relaxed(&state->defaulttimeout, _PYTIME_FROMSECONDS(-1));
#define ADD_EXC(MOD, NAME, VAR, BASE) do { \
VAR = PyErr_NewException("socket." NAME, BASE, NULL); \
diff --git a/Python/fileutils.c b/Python/fileutils.c
index 9529b14d377c60..81276651f6df44 100644
--- a/Python/fileutils.c
+++ b/Python/fileutils.c
@@ -1468,14 +1468,14 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works)
assert(!(atomic_flag_works != NULL && inheritable));
if (atomic_flag_works != NULL && !inheritable) {
- if (*atomic_flag_works == -1) {
+ if (_Py_atomic_load_int_relaxed(atomic_flag_works) == -1) {
int isInheritable = get_inheritable(fd, raise);
if (isInheritable == -1)
return -1;
- *atomic_flag_works = !isInheritable;
+ _Py_atomic_store_int_relaxed(atomic_flag_works, !isInheritable);
}
- if (*atomic_flag_works)
+ if (_Py_atomic_load_int_relaxed(atomic_flag_works))
return 0;
}
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index a1ec1927eb56df..a74779803228c2 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -444,3 +444,5 @@ Modules/readline.c - completed_input_string -
Modules/rotatingtree.c - random_stream -
Modules/rotatingtree.c - random_value -
Modules/rotatingtree.c - random_mutex -
+Modules/socketmodule.c - accept4_works -
+Modules/socketmodule.c - sock_cloexec_works -
https://github.com/python/cpython/commit/ca017a171a20222c056f87551687da08c3…
commit: ca017a171a20222c056f87551687da08c3856a3c
branch: 3.12
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2024-12-31T08:19:45Z
summary:
[3.12] gh-88834: Unify the instance check for typing.Union and types.UnionType (GH-128363) (GH-128371)
Union now uses the instance checks against its parameters instead of
the subclass checks.
(cherry picked from commit b2ac70a62ad1be8e037ce45ccf5f1b753ea5e64b)
Co-authored-by: Serhiy Storchaka <storchaka(a)gmail.com>
files:
A Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
M Lib/test/test_typing.py
M Lib/typing.py
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 0e533757982d35..1da65162a0b300 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -121,7 +121,7 @@ class Sub(Any): pass
def test_errors(self):
with self.assertRaises(TypeError):
- issubclass(42, Any)
+ isinstance(42, Any)
with self.assertRaises(TypeError):
Any[int] # Any is not a generic type.
@@ -136,6 +136,9 @@ class Something: pass
class MockSomething(Something, Mock): pass
self.assertTrue(issubclass(MockSomething, Any))
+ self.assertTrue(issubclass(MockSomething, MockSomething))
+ self.assertTrue(issubclass(MockSomething, Something))
+ self.assertTrue(issubclass(MockSomething, Mock))
ms = MockSomething()
self.assertIsInstance(ms, MockSomething)
self.assertIsInstance(ms, Something)
@@ -1810,13 +1813,81 @@ def test_basics(self):
u = Union[int, float]
self.assertNotEqual(u, Union)
- def test_subclass_error(self):
+ def test_union_isinstance(self):
+ self.assertTrue(isinstance(42, Union[int, str]))
+ self.assertTrue(isinstance('abc', Union[int, str]))
+ self.assertFalse(isinstance(3.14, Union[int, str]))
+ self.assertTrue(isinstance(42, Union[int, list[int]]))
+ self.assertTrue(isinstance(42, Union[int, Any]))
+
+ def test_union_isinstance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[str, list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[list[int], int])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[list[int], str])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[str, Any])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[Any, int])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[Any, str])
+
+ def test_optional_isinstance(self):
+ self.assertTrue(isinstance(42, Optional[int]))
+ self.assertTrue(isinstance(None, Optional[int]))
+ self.assertFalse(isinstance('abc', Optional[int]))
+
+ def test_optional_isinstance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Optional[list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(None, Optional[list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(42, Optional[Any])
+ with self.assertRaises(TypeError):
+ isinstance(None, Optional[Any])
+
+ def test_union_issubclass(self):
+ self.assertTrue(issubclass(int, Union[int, str]))
+ self.assertTrue(issubclass(str, Union[int, str]))
+ self.assertFalse(issubclass(float, Union[int, str]))
+ self.assertTrue(issubclass(int, Union[int, list[int]]))
+ self.assertTrue(issubclass(int, Union[int, Any]))
+ self.assertFalse(issubclass(int, Union[str, Any]))
+ self.assertTrue(issubclass(int, Union[Any, int]))
+ self.assertFalse(issubclass(int, Union[Any, str]))
+
+ def test_union_issubclass_type_error(self):
with self.assertRaises(TypeError):
issubclass(int, Union)
with self.assertRaises(TypeError):
issubclass(Union, int)
with self.assertRaises(TypeError):
issubclass(Union[int, str], int)
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[str, list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[list[int], int])
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[list[int], str])
+
+ def test_optional_issubclass(self):
+ self.assertTrue(issubclass(int, Optional[int]))
+ self.assertTrue(issubclass(type(None), Optional[int]))
+ self.assertFalse(issubclass(str, Optional[int]))
+ self.assertTrue(issubclass(Any, Optional[Any]))
+ self.assertTrue(issubclass(type(None), Optional[Any]))
+ self.assertFalse(issubclass(int, Optional[Any]))
+
+ def test_optional_issubclass_type_error(self):
+ with self.assertRaises(TypeError):
+ issubclass(list[int], Optional[list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(type(None), Optional[list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(int, Optional[list[int]])
def test_union_any(self):
u = Union[Any]
diff --git a/Lib/typing.py b/Lib/typing.py
index a271416d46cc3e..d7f96b60f039c7 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1610,12 +1610,16 @@ def __repr__(self):
return super().__repr__()
def __instancecheck__(self, obj):
- return self.__subclasscheck__(type(obj))
+ for arg in self.__args__:
+ if isinstance(obj, arg):
+ return True
+ return False
def __subclasscheck__(self, cls):
for arg in self.__args__:
if issubclass(cls, arg):
return True
+ return False
def __reduce__(self):
func, (origin, args) = super().__reduce__()
diff --git a/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst b/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
new file mode 100644
index 00000000000000..ca43f914880ba3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
@@ -0,0 +1,3 @@
+Unify the instance check for :class:`typing.Union` and
+:class:`types.UnionType`: :class:`!Union` now uses the instance checks
+against its parameters instead of the subclass checks.
https://github.com/python/cpython/commit/b2ac70a62ad1be8e037ce45ccf5f1b753e…
commit: b2ac70a62ad1be8e037ce45ccf5f1b753ea5e64b
branch: main
author: Serhiy Storchaka <storchaka(a)gmail.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2024-12-31T10:02:58+02:00
summary:
gh-88834: Unify the instance check for typing.Union and types.UnionType (GH-128363)
Union now uses the instance checks against its parameters instead of
the subclass checks.
files:
A Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
M Lib/test/test_typing.py
M Lib/typing.py
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index aa42beca5f9256..ef3cfc9517085e 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -122,7 +122,7 @@ class Sub(Any): pass
def test_errors(self):
with self.assertRaises(TypeError):
- issubclass(42, Any)
+ isinstance(42, Any)
with self.assertRaises(TypeError):
Any[int] # Any is not a generic type.
@@ -137,6 +137,9 @@ class Something: pass
class MockSomething(Something, Mock): pass
self.assertTrue(issubclass(MockSomething, Any))
+ self.assertTrue(issubclass(MockSomething, MockSomething))
+ self.assertTrue(issubclass(MockSomething, Something))
+ self.assertTrue(issubclass(MockSomething, Mock))
ms = MockSomething()
self.assertIsInstance(ms, MockSomething)
self.assertIsInstance(ms, Something)
@@ -2010,13 +2013,81 @@ def test_basics(self):
u = Union[int, float]
self.assertNotEqual(u, Union)
- def test_subclass_error(self):
+ def test_union_isinstance(self):
+ self.assertTrue(isinstance(42, Union[int, str]))
+ self.assertTrue(isinstance('abc', Union[int, str]))
+ self.assertFalse(isinstance(3.14, Union[int, str]))
+ self.assertTrue(isinstance(42, Union[int, list[int]]))
+ self.assertTrue(isinstance(42, Union[int, Any]))
+
+ def test_union_isinstance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[str, list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[list[int], int])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[list[int], str])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[str, Any])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[Any, int])
+ with self.assertRaises(TypeError):
+ isinstance(42, Union[Any, str])
+
+ def test_optional_isinstance(self):
+ self.assertTrue(isinstance(42, Optional[int]))
+ self.assertTrue(isinstance(None, Optional[int]))
+ self.assertFalse(isinstance('abc', Optional[int]))
+
+ def test_optional_isinstance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, Optional[list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(None, Optional[list[int]])
+ with self.assertRaises(TypeError):
+ isinstance(42, Optional[Any])
+ with self.assertRaises(TypeError):
+ isinstance(None, Optional[Any])
+
+ def test_union_issubclass(self):
+ self.assertTrue(issubclass(int, Union[int, str]))
+ self.assertTrue(issubclass(str, Union[int, str]))
+ self.assertFalse(issubclass(float, Union[int, str]))
+ self.assertTrue(issubclass(int, Union[int, list[int]]))
+ self.assertTrue(issubclass(int, Union[int, Any]))
+ self.assertFalse(issubclass(int, Union[str, Any]))
+ self.assertTrue(issubclass(int, Union[Any, int]))
+ self.assertFalse(issubclass(int, Union[Any, str]))
+
+ def test_union_issubclass_type_error(self):
with self.assertRaises(TypeError):
issubclass(int, Union)
with self.assertRaises(TypeError):
issubclass(Union, int)
with self.assertRaises(TypeError):
issubclass(Union[int, str], int)
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[str, list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[list[int], int])
+ with self.assertRaises(TypeError):
+ issubclass(int, Union[list[int], str])
+
+ def test_optional_issubclass(self):
+ self.assertTrue(issubclass(int, Optional[int]))
+ self.assertTrue(issubclass(type(None), Optional[int]))
+ self.assertFalse(issubclass(str, Optional[int]))
+ self.assertTrue(issubclass(Any, Optional[Any]))
+ self.assertTrue(issubclass(type(None), Optional[Any]))
+ self.assertFalse(issubclass(int, Optional[Any]))
+
+ def test_optional_issubclass_type_error(self):
+ with self.assertRaises(TypeError):
+ issubclass(list[int], Optional[list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(type(None), Optional[list[int]])
+ with self.assertRaises(TypeError):
+ issubclass(int, Optional[list[int]])
def test_union_any(self):
u = Union[Any]
diff --git a/Lib/typing.py b/Lib/typing.py
index 5f3aacd877221c..e69b485422cbd2 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1733,12 +1733,16 @@ def __repr__(self):
return super().__repr__()
def __instancecheck__(self, obj):
- return self.__subclasscheck__(type(obj))
+ for arg in self.__args__:
+ if isinstance(obj, arg):
+ return True
+ return False
def __subclasscheck__(self, cls):
for arg in self.__args__:
if issubclass(cls, arg):
return True
+ return False
def __reduce__(self):
func, (origin, args) = super().__reduce__()
diff --git a/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst b/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
new file mode 100644
index 00000000000000..ca43f914880ba3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-12-30-20-48-28.gh-issue-88834.RIvgwc.rst
@@ -0,0 +1,3 @@
+Unify the instance check for :class:`typing.Union` and
+:class:`types.UnionType`: :class:`!Union` now uses the instance checks
+against its parameters instead of the subclass checks.
https://github.com/python/cpython/commit/7c72c1f0dfff8950e3c6f656307099f1b0…
commit: 7c72c1f0dfff8950e3c6f656307099f1b0a4f8a3
branch: main
author: Kumar Aditya <kumaraditya(a)python.org>
committer: kumaraditya303 <kumaraditya(a)python.org>
date: 2024-12-31T11:50:35+05:30
summary:
gh-128277: use relaxed atomics for `sock_fd` (#128304)
files:
M Modules/socketmodule.c
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 1e95be9b1bc9f4..1f0cbf6abb184c 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -110,6 +110,7 @@ Local naming conventions:
#include "pycore_fileutils.h" // _Py_set_inheritable()
#include "pycore_moduleobject.h" // _PyModule_GetState
#include "pycore_time.h" // _PyTime_AsMilliseconds()
+#include "pycore_pyatomic_ft_wrappers.h"
#ifdef _Py_MEMORY_SANITIZER
# include <sanitizer/msan_interface.h>
@@ -564,6 +565,42 @@ typedef struct _socket_state {
#endif
} socket_state;
+static inline void
+set_sock_fd(PySocketSockObject *s, SOCKET_T fd)
+{
+#ifdef Py_GIL_DISABLED
+#if SIZEOF_SOCKET_T == SIZEOF_INT
+ _Py_atomic_store_int_relaxed((int *)&s->sock_fd, (int)fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG
+ _Py_atomic_store_long_relaxed((long *)&s->sock_fd, (long)fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG
+ _Py_atomic_store_llong_relaxed((long long *)&s->sock_fd, (long long)fd);
+#else
+ #error "Unsupported SIZEOF_SOCKET_T"
+#endif
+#else
+ s->sock_fd = fd;
+#endif
+}
+
+static inline SOCKET_T
+get_sock_fd(PySocketSockObject *s)
+{
+#ifdef Py_GIL_DISABLED
+#if SIZEOF_SOCKET_T == SIZEOF_INT
+ return (SOCKET_T)_Py_atomic_load_int_relaxed((int *)&s->sock_fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG
+ return (SOCKET_T)_Py_atomic_load_long_relaxed((long *)&s->sock_fd);
+#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG
+ return (SOCKET_T)_Py_atomic_load_llong_relaxed((long long *)&s->sock_fd);
+#else
+ #error "Unsupported SIZEOF_SOCKET_T"
+#endif
+#else
+ return s->sock_fd;
+#endif
+}
+
static inline socket_state *
get_module_state(PyObject *mod)
{
@@ -736,10 +773,10 @@ internal_setblocking(PySocketSockObject *s, int block)
#ifndef MS_WINDOWS
#if (defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO))
block = !block;
- if (ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block) == -1)
+ if (ioctl(get_sock_fd(s), FIONBIO, (unsigned int *)&block) == -1)
goto done;
#else
- delay_flag = fcntl(s->sock_fd, F_GETFL, 0);
+ delay_flag = fcntl(get_sock_fd(s), F_GETFL, 0);
if (delay_flag == -1)
goto done;
if (block)
@@ -747,12 +784,12 @@ internal_setblocking(PySocketSockObject *s, int block)
else
new_delay_flag = delay_flag | O_NONBLOCK;
if (new_delay_flag != delay_flag)
- if (fcntl(s->sock_fd, F_SETFL, new_delay_flag) == -1)
+ if (fcntl(get_sock_fd(s), F_SETFL, new_delay_flag) == -1)
goto done;
#endif
#else /* MS_WINDOWS */
arg = !block;
- if (ioctlsocket(s->sock_fd, FIONBIO, &arg) != 0)
+ if (ioctlsocket(get_sock_fd(s), FIONBIO, &arg) != 0)
goto done;
#endif /* MS_WINDOWS */
@@ -792,13 +829,13 @@ internal_select(PySocketSockObject *s, int writing, PyTime_t interval,
assert(!(connect && !writing));
/* Guard against closed socket */
- if (s->sock_fd == INVALID_SOCKET)
+ if (get_sock_fd(s) == INVALID_SOCKET)
return 0;
/* Prefer poll, if available, since you can poll() any fd
* which can't be done with select(). */
#ifdef HAVE_POLL
- pollfd.fd = s->sock_fd;
+ pollfd.fd = get_sock_fd(s);
pollfd.events = writing ? POLLOUT : POLLIN;
if (connect) {
/* On Windows, the socket becomes writable on connection success,
@@ -838,23 +875,23 @@ internal_select(PySocketSockObject *s, int writing, PyTime_t interval,
tvp = NULL;
FD_ZERO(&fds);
- FD_SET(s->sock_fd, &fds);
+ FD_SET(get_sock_fd(s), &fds);
FD_ZERO(&efds);
if (connect) {
/* On Windows, the socket becomes writable on connection success,
but a connection failure is notified as an error. On POSIX, the
socket becomes writable on connection success or on connection
failure. */
- FD_SET(s->sock_fd, &efds);
+ FD_SET(get_sock_fd(s), &efds);
}
/* See if the socket is ready */
Py_BEGIN_ALLOW_THREADS;
if (writing)
- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
+ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int),
NULL, &fds, &efds, tvp);
else
- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
+ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int),
&fds, NULL, &efds, tvp);
Py_END_ALLOW_THREADS;
#endif
@@ -1030,7 +1067,7 @@ static int
init_sockobject(socket_state *state, PySocketSockObject *s,
SOCKET_T fd, int family, int type, int proto)
{
- s->sock_fd = fd;
+ set_sock_fd(s, fd);
s->sock_family = family;
s->sock_type = type;
@@ -2127,7 +2164,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
}
strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name));
ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0';
- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
PyBuffer_Release(&haddr);
return 0;
@@ -2252,7 +2289,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
} else if ((size_t)len < sizeof(ifr.ifr_name)) {
strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name));
ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0';
- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
Py_DECREF(interfaceName);
return 0;
@@ -2296,7 +2333,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
} else if ((size_t)len < sizeof(ifr.ifr_name)) {
strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name));
ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0';
- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
Py_DECREF(interfaceName);
return 0;
@@ -2344,7 +2381,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
} else if ((size_t)len < sizeof(ifr.ifr_name)) {
strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name));
ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0';
- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) {
s->errorhandler();
Py_DECREF(interfaceName);
return 0;
@@ -2403,7 +2440,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
sizeof(info.ctl_name));
Py_DECREF(ctl_name);
- if (ioctl(s->sock_fd, CTLIOCGINFO, &info)) {
+ if (ioctl(get_sock_fd(s), CTLIOCGINFO, &info)) {
PyErr_SetString(PyExc_OSError,
"cannot find kernel control with provided name");
return 0;
@@ -2869,7 +2906,7 @@ sock_accept_impl(PySocketSockObject *s, void *data)
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
socket_state *state = s->state;
if (state->accept4_works != 0) {
- ctx->result = accept4(s->sock_fd, addr, paddrlen,
+ ctx->result = accept4(get_sock_fd(s), addr, paddrlen,
SOCK_CLOEXEC);
if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) {
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
@@ -2877,9 +2914,9 @@ sock_accept_impl(PySocketSockObject *s, void *data)
}
}
if (state->accept4_works == 0)
- ctx->result = accept(s->sock_fd, addr, paddrlen);
+ ctx->result = accept(get_sock_fd(s), addr, paddrlen);
#else
- ctx->result = accept(s->sock_fd, addr, paddrlen);
+ ctx->result = accept(get_sock_fd(s), addr, paddrlen);
#endif
#ifdef MS_WINDOWS
@@ -2946,7 +2983,7 @@ sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
goto finally;
}
- addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
+ addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf),
addrlen, s->sock_proto);
if (addr == NULL)
goto finally;
@@ -3158,7 +3195,7 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
if (PyArg_ParseTuple(args, "iiK:setsockopt",
&level, &optname, &vflag)) {
// level should always be set to AF_VSOCK
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
(void*)&vflag, sizeof vflag);
goto done;
}
@@ -3172,7 +3209,7 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
#ifdef MS_WINDOWS
if (optname == SIO_TCP_SET_ACK_FREQUENCY) {
int dummy;
- res = WSAIoctl(s->sock_fd, SIO_TCP_SET_ACK_FREQUENCY, &flag,
+ res = WSAIoctl(get_sock_fd(s), SIO_TCP_SET_ACK_FREQUENCY, &flag,
sizeof(flag), NULL, 0, &dummy, NULL, NULL);
if (res >= 0) {
s->quickack = flag;
@@ -3180,7 +3217,7 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
goto done;
}
#endif
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
(char*)&flag, sizeof flag);
goto done;
}
@@ -3190,7 +3227,7 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
if (PyArg_ParseTuple(args, "iiO!I:setsockopt",
&level, &optname, Py_TYPE(Py_None), &none, &optlen)) {
assert(sizeof(socklen_t) >= sizeof(unsigned int));
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
NULL, (socklen_t)optlen);
goto done;
}
@@ -3209,10 +3246,10 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
INT_MAX);
return NULL;
}
- res = setsockopt(s->sock_fd, level, optname,
+ res = setsockopt(get_sock_fd(s), level, optname,
optval.buf, (int)optval.len);
#else
- res = setsockopt(s->sock_fd, level, optname, optval.buf, optval.len);
+ res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len);
#endif
PyBuffer_Release(&optval);
@@ -3259,7 +3296,7 @@ sock_getsockopt(PySocketSockObject *s, PyObject *args)
if (s->sock_family == AF_VSOCK) {
uint64_t vflag = 0; // Must be set width of 64 bits
flagsize = sizeof vflag;
- res = getsockopt(s->sock_fd, level, optname,
+ res = getsockopt(get_sock_fd(s), level, optname,
(void *)&vflag, &flagsize);
if (res < 0)
return s->errorhandler();
@@ -3272,7 +3309,7 @@ sock_getsockopt(PySocketSockObject *s, PyObject *args)
}
#endif
flagsize = sizeof flag;
- res = getsockopt(s->sock_fd, level, optname,
+ res = getsockopt(get_sock_fd(s), level, optname,
(void *)&flag, &flagsize);
if (res < 0)
return s->errorhandler();
@@ -3293,7 +3330,7 @@ sock_getsockopt(PySocketSockObject *s, PyObject *args)
buf = PyBytes_FromStringAndSize((char *)NULL, buflen);
if (buf == NULL)
return NULL;
- res = getsockopt(s->sock_fd, level, optname,
+ res = getsockopt(get_sock_fd(s), level, optname,
(void *)PyBytes_AS_STRING(buf), &buflen);
if (res < 0) {
Py_DECREF(buf);
@@ -3330,7 +3367,7 @@ sock_bind(PySocketSockObject *s, PyObject *addro)
}
Py_BEGIN_ALLOW_THREADS
- res = bind(s->sock_fd, SAS2SA(&addrbuf), addrlen);
+ res = bind(get_sock_fd(s), SAS2SA(&addrbuf), addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
@@ -3367,9 +3404,9 @@ _socket_socket_close_impl(PySocketSockObject *s)
SOCKET_T fd;
int res;
- fd = s->sock_fd;
+ fd = get_sock_fd(s);
if (fd != INVALID_SOCKET) {
- s->sock_fd = INVALID_SOCKET;
+ set_sock_fd(s, INVALID_SOCKET);
/* We do not want to retry upon EINTR: see
http://lwn.net/Articles/576478/ and
@@ -3390,8 +3427,8 @@ _socket_socket_close_impl(PySocketSockObject *s)
static PyObject *
sock_detach(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
{
- SOCKET_T fd = s->sock_fd;
- s->sock_fd = INVALID_SOCKET;
+ SOCKET_T fd = get_sock_fd(s);
+ set_sock_fd(s, INVALID_SOCKET);
return PyLong_FromSocket_t(fd);
}
@@ -3409,7 +3446,7 @@ sock_connect_impl(PySocketSockObject *s, void* Py_UNUSED(data))
int err;
socklen_t size = sizeof err;
- if (getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, (void *)&err, &size)) {
+ if (getsockopt(get_sock_fd(s), SOL_SOCKET, SO_ERROR, (void *)&err, &size)) {
/* getsockopt() failed */
return 0;
}
@@ -3443,7 +3480,7 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
int res, err, wait_connect;
Py_BEGIN_ALLOW_THREADS
- res = connect(s->sock_fd, addr, addrlen);
+ res = connect(get_sock_fd(s), addr, addrlen);
Py_END_ALLOW_THREADS
if (!res) {
@@ -3573,7 +3610,7 @@ instead of raising an exception when an error occurs.");
static PyObject *
sock_fileno(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
{
- return PyLong_FromSocket_t(s->sock_fd);
+ return PyLong_FromSocket_t(get_sock_fd(s));
}
PyDoc_STRVAR(fileno_doc,
@@ -3596,11 +3633,11 @@ sock_getsockname(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
return NULL;
memset(&addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
- res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
+ res = getsockname(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen,
s->sock_proto);
}
@@ -3628,11 +3665,11 @@ sock_getpeername(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
return NULL;
memset(&addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
- res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
+ res = getpeername(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen,
s->sock_proto);
}
@@ -3664,7 +3701,7 @@ sock_listen(PySocketSockObject *s, PyObject *args)
* (which doesn't make sense anyway) we force a minimum value of 0. */
if (backlog < 0)
backlog = 0;
- res = listen(s->sock_fd, backlog);
+ res = listen(get_sock_fd(s), backlog);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
@@ -3695,9 +3732,9 @@ sock_recv_impl(PySocketSockObject *s, void *data)
#ifdef MS_WINDOWS
if (ctx->len > INT_MAX)
ctx->len = INT_MAX;
- ctx->result = recv(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags);
+ ctx->result = recv(get_sock_fd(s), ctx->cbuf, (int)ctx->len, ctx->flags);
#else
- ctx->result = recv(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags);
+ ctx->result = recv(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags);
#endif
return (ctx->result >= 0);
}
@@ -3866,10 +3903,10 @@ sock_recvfrom_impl(PySocketSockObject *s, void *data)
#ifdef MS_WINDOWS
if (ctx->len > INT_MAX)
ctx->len = INT_MAX;
- ctx->result = recvfrom(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags,
+ ctx->result = recvfrom(get_sock_fd(s), ctx->cbuf, (int)ctx->len, ctx->flags,
SAS2SA(ctx->addrbuf), ctx->addrlen);
#else
- ctx->result = recvfrom(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags,
+ ctx->result = recvfrom(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags,
SAS2SA(ctx->addrbuf), ctx->addrlen);
#endif
return (ctx->result >= 0);
@@ -3913,7 +3950,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
if (sock_call(s, 0, sock_recvfrom_impl, &ctx) < 0)
return -1;
- *addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
+ *addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen,
s->sock_proto);
if (*addr == NULL)
return -1;
@@ -4044,7 +4081,7 @@ sock_recvmsg_impl(PySocketSockObject *s, void *data)
{
struct sock_recvmsg *ctx = data;
- ctx->result = recvmsg(s->sock_fd, ctx->msg, ctx->flags);
+ ctx->result = recvmsg(get_sock_fd(s), ctx->msg, ctx->flags);
return (ctx->result >= 0);
}
@@ -4153,7 +4190,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
(*makeval)(ctx.result, makeval_data),
cmsg_list,
(int)msg.msg_flags,
- makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
+ makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf),
((msg.msg_namelen > addrbuflen) ?
addrbuflen : msg.msg_namelen),
s->sock_proto));
@@ -4372,9 +4409,9 @@ sock_send_impl(PySocketSockObject *s, void *data)
#ifdef MS_WINDOWS
if (ctx->len > INT_MAX)
ctx->len = INT_MAX;
- ctx->result = send(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags);
+ ctx->result = send(get_sock_fd(s), ctx->buf, (int)ctx->len, ctx->flags);
#else
- ctx->result = send(s->sock_fd, ctx->buf, ctx->len, ctx->flags);
+ ctx->result = send(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags);
#endif
return (ctx->result >= 0);
}
@@ -4511,10 +4548,10 @@ sock_sendto_impl(PySocketSockObject *s, void *data)
#ifdef MS_WINDOWS
if (ctx->len > INT_MAX)
ctx->len = INT_MAX;
- ctx->result = sendto(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags,
+ ctx->result = sendto(get_sock_fd(s), ctx->buf, (int)ctx->len, ctx->flags,
SAS2SA(ctx->addrbuf), ctx->addrlen);
#else
- ctx->result = sendto(s->sock_fd, ctx->buf, ctx->len, ctx->flags,
+ ctx->result = sendto(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags,
SAS2SA(ctx->addrbuf), ctx->addrlen);
#endif
return (ctx->result >= 0);
@@ -4660,7 +4697,7 @@ sock_sendmsg_impl(PySocketSockObject *s, void *data)
{
struct sock_sendmsg *ctx = data;
- ctx->result = sendmsg(s->sock_fd, ctx->msg, ctx->flags);
+ ctx->result = sendmsg(get_sock_fd(s), ctx->msg, ctx->flags);
return (ctx->result >= 0);
}
@@ -5048,7 +5085,7 @@ sock_shutdown(PySocketSockObject *s, PyObject *arg)
if (how == -1 && PyErr_Occurred())
return NULL;
Py_BEGIN_ALLOW_THREADS
- res = shutdown(s->sock_fd, how);
+ res = shutdown(get_sock_fd(s), how);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
@@ -5078,7 +5115,7 @@ sock_ioctl(PySocketSockObject *s, PyObject *arg)
unsigned int option = RCVALL_ON;
if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option))
return NULL;
- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option),
+ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option),
NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) {
return set_error();
}
@@ -5088,7 +5125,7 @@ sock_ioctl(PySocketSockObject *s, PyObject *arg)
if (!PyArg_ParseTuple(arg, "k(kkk):ioctl", &cmd,
&ka.onoff, &ka.keepalivetime, &ka.keepaliveinterval))
return NULL;
- if (WSAIoctl(s->sock_fd, cmd, &ka, sizeof(ka),
+ if (WSAIoctl(get_sock_fd(s), cmd, &ka, sizeof(ka),
NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) {
return set_error();
}
@@ -5098,7 +5135,7 @@ sock_ioctl(PySocketSockObject *s, PyObject *arg)
unsigned int option;
if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option))
return NULL;
- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option),
+ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option),
NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) {
return set_error();
}
@@ -5130,7 +5167,7 @@ sock_share(PySocketSockObject *s, PyObject *arg)
return NULL;
Py_BEGIN_ALLOW_THREADS
- result = WSADuplicateSocketW(s->sock_fd, processId, &info);
+ result = WSADuplicateSocketW(get_sock_fd(s), processId, &info);
Py_END_ALLOW_THREADS
if (result == SOCKET_ERROR)
return set_error();
@@ -5264,7 +5301,7 @@ sock_finalize(PySocketSockObject *s)
/* Save the current exception, if any. */
PyObject *exc = PyErr_GetRaisedException();
- if (s->sock_fd != INVALID_SOCKET) {
+ if (get_sock_fd(s) != INVALID_SOCKET) {
if (PyErr_ResourceWarning((PyObject *)s, 1, "unclosed %R", s)) {
/* Spurious errors can appear at shutdown */
if (PyErr_ExceptionMatches(PyExc_Warning)) {
@@ -5276,8 +5313,8 @@ sock_finalize(PySocketSockObject *s)
to allow the logger to call socket methods like
socket.getsockname(). If the socket is closed before, socket
methods fails with the EBADF error. */
- fd = s->sock_fd;
- s->sock_fd = INVALID_SOCKET;
+ fd = get_sock_fd(s);
+ set_sock_fd(s, INVALID_SOCKET);
/* We do not want to retry upon EINTR: see sock_close() */
Py_BEGIN_ALLOW_THREADS
@@ -5314,11 +5351,11 @@ sock_repr(PySocketSockObject *s)
{
long sock_fd;
/* On Windows, this test is needed because SOCKET_T is unsigned */
- if (s->sock_fd == INVALID_SOCKET) {
+ if (get_sock_fd(s) == INVALID_SOCKET) {
sock_fd = -1;
}
#if SIZEOF_SOCKET_T > SIZEOF_LONG
- else if (s->sock_fd > LONG_MAX) {
+ else if (get_sock_fd(s) > LONG_MAX) {
/* this can occur on Win64, and actually there is a special
ugly printf formatter for decimal pointer length integer
printing, only bother if necessary*/
@@ -5329,7 +5366,7 @@ sock_repr(PySocketSockObject *s)
}
#endif
else
- sock_fd = (long)s->sock_fd;
+ sock_fd = (long)get_sock_fd(s);
return PyUnicode_FromFormat(
"<socket object, fd=%ld, family=%d, type=%d, proto=%d>",
sock_fd, s->sock_family,
https://github.com/python/cpython/commit/7ef49074123511003c8b7f7f3ba2a4e052…
commit: 7ef49074123511003c8b7f7f3ba2a4e05285e8dc
branch: main
author: Ken Jin <kenjin(a)python.org>
committer: Fidget-Spinner <kenjin4096(a)gmail.com>
date: 2024-12-31T12:24:17+08:00
summary:
gh-128262: Allow specialization of calls to classes with __slots__ (GH-128263)
files:
M Include/internal/pycore_uop_metadata.h
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/specialize.c
diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h
index e71194b116e020..73fc29eb78a7a4 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -234,7 +234,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_CALL_STR_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
- [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG,
+ [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 63cf1978e8abe5..602cf7f47b812b 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -3765,13 +3765,15 @@ dummy_func(
DEOPT_IF(!PyType_Check(callable_o));
PyTypeObject *tp = (PyTypeObject *)callable_o;
DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version);
- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES);
+ assert(tp->tp_new == PyBaseObject_Type.tp_new);
+ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
+ assert(tp->tp_alloc == PyType_GenericAlloc);
PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o;
PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init);
PyCodeObject *code = (PyCodeObject *)init_func->func_code;
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize));
STAT_INC(CALL, hit);
- PyObject *self_o = _PyType_NewManagedObject(tp);
+ PyObject *self_o = PyType_GenericAlloc(tp, 0);
if (self_o == NULL) {
ERROR_NO_POP();
}
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 22335021faaa6d..f7374d52705960 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -4572,7 +4572,9 @@
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES);
+ assert(tp->tp_new == PyBaseObject_Type.tp_new);
+ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
+ assert(tp->tp_alloc == PyType_GenericAlloc);
PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o;
PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init);
PyCodeObject *code = (PyCodeObject *)init_func->func_code;
@@ -4581,7 +4583,9 @@
JUMP_TO_JUMP_TARGET();
}
STAT_INC(CALL, hit);
- PyObject *self_o = _PyType_NewManagedObject(tp);
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ PyObject *self_o = PyType_GenericAlloc(tp, 0);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
if (self_o == NULL) {
JUMP_TO_ERROR();
}
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index bed16b60b76a2f..98743c27c38524 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -1048,13 +1048,17 @@
DEOPT_IF(!PyType_Check(callable_o), CALL);
PyTypeObject *tp = (PyTypeObject *)callable_o;
DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version, CALL);
- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES);
+ assert(tp->tp_new == PyBaseObject_Type.tp_new);
+ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
+ assert(tp->tp_alloc == PyType_GenericAlloc);
PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o;
PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init);
PyCodeObject *code = (PyCodeObject *)init_func->func_code;
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize), CALL);
STAT_INC(CALL, hit);
- PyObject *self_o = _PyType_NewManagedObject(tp);
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ PyObject *self_o = PyType_GenericAlloc(tp, 0);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
if (self_o == NULL) {
goto error;
}
diff --git a/Python/specialize.c b/Python/specialize.c
index 2148b62c3a1953..c918c77779d20d 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -2002,10 +2002,6 @@ get_init_for_simple_managed_python_class(PyTypeObject *tp, unsigned int *tp_vers
return NULL;
}
unsigned long tp_flags = PyType_GetFlags(tp);
- if ((tp_flags & Py_TPFLAGS_INLINE_VALUES) == 0) {
- SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_INIT_NOT_INLINE_VALUES);
- return NULL;
- }
if (!(tp_flags & Py_TPFLAGS_HEAPTYPE)) {
/* Is this possible? */
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_EXPECTED_ERROR);
https://github.com/python/cpython/commit/62729d79206014886f5de2b62a5824436e…
commit: 62729d79206014886f5de2b62a5824436e18b66f
branch: 3.13
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: gpshead <greg(a)krypto.org>
date: 2024-12-30T21:15:44Z
summary:
[3.13] gh-128342: Specify timeout unit in subprocess docstrings (GH-128343) (#128365)
gh-128342: Specify timeout unit in subprocess docstrings (GH-128343)
Specify timeout unit (seconds) in subprocess docstrings
(cherry picked from commit dafe7a44630aa32bb411cceb45c7b7df725e3fe3)
Co-authored-by: n-l-i <57808975+n-l-i(a)users.noreply.github.com>
Co-authored-by: Terry Jan Reedy <tjreedy(a)udel.edu>
files:
M Lib/subprocess.py
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index b2dcb1454c139e..f614c903c8837c 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -386,7 +386,7 @@ def _text_encoding():
def call(*popenargs, timeout=None, **kwargs):
"""Run command with arguments. Wait for command to complete or
- timeout, then return the returncode attribute.
+ for timeout seconds, then return the returncode attribute.
The arguments are the same as for the Popen constructor. Example:
@@ -523,8 +523,8 @@ def run(*popenargs,
in the returncode attribute, and output & stderr attributes if those streams
were captured.
- If timeout is given, and the process takes too long, a TimeoutExpired
- exception will be raised.
+ If timeout (seconds) is given and the process takes too long,
+ a TimeoutExpired exception will be raised.
There is an optional argument "input", allowing you to
pass bytes or a string to the subprocess's stdin. If you use this argument