Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-greenlet for openSUSE:Factory
checked in at 2025-09-02 17:58:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-greenlet (Old)
and /work/SRC/openSUSE:Factory/.python-greenlet.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-greenlet"
Tue Sep 2 17:58:00 2025 rev:55 rq:1302236 version:3.2.4
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-greenlet/python-greenlet.changes
2025-06-14 16:17:15.933119463 +0200
+++
/work/SRC/openSUSE:Factory/.python-greenlet.new.1977/python-greenlet.changes
2025-09-02 17:58:07.169983962 +0200
@@ -1,0 +2,13 @@
+Mon Sep 1 12:37:08 UTC 2025 - John Paul Adrian Glaubitz
<[email protected]>
+
+- Update to 3.2.4
+ * Various small build/test changes for less common configurations (e.g.,
+ building CPython with assertions enabled but NOT debugging),
+ contributed by Michał Górny. Note that while greenlet will BUILD in
+ a free-threaded Python, it will cause the GIL to be allocated and
+ used, and memory may leak. Also note that these configurations
+ are not tested by this project's CI.
+ * Fix an assertion error on debug builds of Python 3.14 when using the
+ experimental JIT. See PR 460.
+
+-------------------------------------------------------------------
Old:
----
greenlet-3.2.3.tar.gz
New:
----
greenlet-3.2.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-greenlet.spec ++++++
--- /var/tmp/diff_new_pack.MBgYLb/_old 2025-09-02 17:58:07.830011737 +0200
+++ /var/tmp/diff_new_pack.MBgYLb/_new 2025-09-02 17:58:07.830011737 +0200
@@ -22,7 +22,7 @@
%{?sle15_python_module_pythons}
Name: python-greenlet
-Version: 3.2.3
+Version: 3.2.4
Release: 0
Summary: Lightweight in-process concurrent programming
License: MIT
++++++ greenlet-3.2.3.tar.gz -> greenlet-3.2.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/.github/workflows/tests.yml
new/greenlet-3.2.4/.github/workflows/tests.yml
--- old/greenlet-3.2.3/.github/workflows/tests.yml 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/.github/workflows/tests.yml 2025-08-07
15:13:36.000000000 +0200
@@ -22,7 +22,7 @@
runs-on: ${{ matrix.os }}
strategy:
matrix:
- python-version: [3.9, "3.10", "3.11", "3.12", "3.13", "3.14.0-beta.2"]
+ python-version: [3.9, "3.10", "3.11", "3.12", "3.13", "3.14.0-rc.1"]
# Recall the macOS builds upload built wheels so all supported versions
# need to run on mac.
os: [ubuntu-latest, macos-latest]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/CHANGES.rst
new/greenlet-3.2.4/CHANGES.rst
--- old/greenlet-3.2.3/CHANGES.rst 2025-06-05 18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/CHANGES.rst 2025-08-07 15:13:36.000000000 +0200
@@ -2,6 +2,24 @@
Changes
=========
+3.2.4 (2025-08-07)
+==================
+
+.. note::
+
+ The 3.2.x series will be the last to support Python 3.9.
+
+- Various small build/test changes for less common configurations (e.g.,
+ building CPython with assertions enabled but NOT debugging),
+ contributed by Michał Górny. Note that while greenlet will BUILD in
+ a free-threaded Python, it will cause the GIL to be allocated and
+ used, and memory may leak. Also note that these configurations
+ are not tested by this project's CI.
+- Fix an assertion error on debug builds of Python 3.14 when using the
+ experimental JIT. See :issue:`460
+ <https://github.com/python-greenlet/greenlet/issues/460>`_.
+
+
3.2.3 (2025-06-05)
==================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/PKG-INFO new/greenlet-3.2.4/PKG-INFO
--- old/greenlet-3.2.3/PKG-INFO 2025-06-05 18:08:19.273496000 +0200
+++ new/greenlet-3.2.4/PKG-INFO 2025-08-07 15:13:39.288525800 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: greenlet
-Version: 3.2.3
+Version: 3.2.4
Summary: Lightweight in-process concurrent programming
Home-page: https://greenlet.readthedocs.io/
Author: Alexey Borzenkov
@@ -38,6 +38,7 @@
Provides-Extra: test
Requires-Dist: objgraph; extra == "test"
Requires-Dist: psutil; extra == "test"
+Requires-Dist: setuptools; extra == "test"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/appveyor.yml
new/greenlet-3.2.4/appveyor.yml
--- old/greenlet-3.2.3/appveyor.yml 2025-06-05 18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/appveyor.yml 2025-08-07 15:13:36.000000000 +0200
@@ -40,7 +40,7 @@
# Fully supported 64-bit versions, with testing. This should be
# all the current (non EOL) versions.
- PYTHON: "C:\\Python314-x64"
- PYTHON_VERSION: "3.14.0b2"
+ PYTHON_VERSION: "3.14.0rc1"
PYTHON_ARCH: "64"
PYTHON_EXE: python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/docs/caveats.rst
new/greenlet-3.2.4/docs/caveats.rst
--- old/greenlet-3.2.3/docs/caveats.rst 2025-06-05 18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/docs/caveats.rst 2025-08-07 15:13:36.000000000 +0200
@@ -32,3 +32,18 @@
lead to a hang.
See :issue:`143` for an example.
+
+Free-threading Is Not Supported
+===============================
+
+Beginning with 3.14 (and experimental in 3.13), CPython may be built
+in a free-threaded mode where the GIL is not used by default. greenlet
+does not support this mode (although it will build with it), and using
+greenlet in such an interpreter will cause the GIL to be enabled.
+
+In addition, there are known issues running greenlets in a
+free-threaded CPython. These include:
+
+- Garbage collection differences may cause ``GreenletExit`` to no
+ longer be raised in certain multi-threaded scenarios.
+- There may be other memory leaks.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/docs/index.rst
new/greenlet-3.2.4/docs/index.rst
--- old/greenlet-3.2.3/docs/index.rst 2025-06-05 18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/docs/index.rst 2025-08-07 15:13:36.000000000 +0200
@@ -80,6 +80,10 @@
when they execute, and since they are coroutines, many greenlets can
exist in a single native thread.
+Note that greenlet will cause a free-threaded build of Python to
+allocate a GIL, so no actual free-threading will take place. For more
+on free-threading and greenlet, see :doc:`caveats`.
+
.. rubric:: How are greenlets different from threads?
Threads (in theory) are preemptive and parallel [#f1]_, meaning that multiple
@@ -102,6 +106,10 @@
require fewer resources; it is often practical to have many more
greenlets than it is threads.
+Note that greenlet will cause a free-threaded build of Python to
+allocate a GIL, so no actual free-threading will take place. For more
+on free-threading and greenlet, see :doc:`caveats`.
+
.. _race conditions: https://en.wikipedia.org/wiki/Race_condition
.. _deadlocks:
https://docs.microsoft.com/en-us/troubleshoot/dotnet/visual-basic/race-conditions-deadlocks#when-deadlocks-occur
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/setup.py new/greenlet-3.2.4/setup.py
--- old/greenlet-3.2.3/setup.py 2025-06-05 18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/setup.py 2025-08-07 15:13:36.000000000 +0200
@@ -260,6 +260,7 @@
'test': [
'objgraph',
'psutil',
+ 'setuptools',
],
},
python_requires=">=3.9",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/PyGreenlet.cpp
new/greenlet-3.2.4/src/greenlet/PyGreenlet.cpp
--- old/greenlet-3.2.3/src/greenlet/PyGreenlet.cpp 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/PyGreenlet.cpp 2025-08-07
15:13:36.000000000 +0200
@@ -56,8 +56,15 @@
PyGreenlet* o =
(PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple,
mod_globs->empty_dict);
if (o) {
- new UserGreenlet(o, GET_THREAD_STATE().state().borrow_current());
+ // Recall: borrowing or getting the current greenlet
+ // causes the "deleteme list" to get cleared. So constructing a
greenlet
+ // can do things like cause other greenlets to get finalized.
+ UserGreenlet* c = new UserGreenlet(o,
GET_THREAD_STATE().state().borrow_current());
assert(Py_REFCNT(o) == 1);
+ // Also: This looks like a memory leak, but isn't. Constructing the
+ // C++ object assigns it to the pimpl pointer of the Python object (o);
+ // we'll need that later.
+ assert(c == o->pimpl);
}
return o;
}
@@ -236,20 +243,26 @@
* and call ``PyObject_CallFinalizerFromDealloc``,
* but that's only supported in Python 3.4+; see
* Modules/_io/iobase.c for an example.
+ * TODO: We no longer run on anything that old, switch to finalizers.
*
* The following approach is copied from iobase.c in CPython 2.7.
* (along with much of this function in general). Here's their
* comment:
*
* When called from a heap type's dealloc, the type will be
- * decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */
+ * decref'ed on return (see e.g. subtype_dealloc in typeobject.c).
+ *
+ * On free-threaded builds of CPython, the type is meant to be immortal
+ * so we probably shouldn't mess with this? See
+ * test_issue_245_reference_counting_subclass_no_threads
+ */
if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) {
Py_INCREF(self.TYPE());
}
PyObject_GC_Track((PyObject*)self);
- _Py_DEC_REFTOTAL;
+ GREENLET_Py_DEC_REFTOTAL;
#ifdef COUNT_ALLOCS
--Py_TYPE(self)->tp_frees;
--Py_TYPE(self)->tp_allocs;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/TGreenlet.cpp
new/greenlet-3.2.4/src/greenlet/TGreenlet.cpp
--- old/greenlet-3.2.3/src/greenlet/TGreenlet.cpp 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/TGreenlet.cpp 2025-08-07
15:13:36.000000000 +0200
@@ -562,6 +562,7 @@
// be able to raise an exception.
// That's mostly OK! Since we can't add it to a list, our refcount
// won't increase, and we'll go ahead with the DECREFs later.
+
ThreadState *const thread_state = this->thread_state();
if (thread_state) {
thread_state->delete_when_thread_running(this->self());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/TGreenlet.hpp
new/greenlet-3.2.4/src/greenlet/TGreenlet.hpp
--- old/greenlet-3.2.3/src/greenlet/TGreenlet.hpp 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/TGreenlet.hpp 2025-08-07
15:13:36.000000000 +0200
@@ -116,6 +116,12 @@
#endif
#if GREENLET_PY314
int py_recursion_depth;
+ // I think this is only used by the JIT. At least,
+ // we only got errors not switching it when the JIT was enabled.
+ // Python/generated_cases.c.h:12469: _PyEval_EvalFrameDefault:
+ // Assertion `tstate->current_executor == NULL' failed.
+ // see https://github.com/python-greenlet/greenlet/issues/460
+ PyObject* current_executor;
#elif GREENLET_PY312
int py_recursion_depth;
int c_recursion_depth;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/TPythonState.cpp
new/greenlet-3.2.4/src/greenlet/TPythonState.cpp
--- old/greenlet-3.2.3/src/greenlet/TPythonState.cpp 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/TPythonState.cpp 2025-08-07
15:13:36.000000000 +0200
@@ -14,6 +14,7 @@
#endif
#if GREENLET_PY314
,py_recursion_depth(0)
+ ,current_executor(nullptr)
#elif GREENLET_PY312
,py_recursion_depth(0)
,c_recursion_depth(0)
@@ -136,6 +137,7 @@
#if GREENLET_PY311
#if GREENLET_PY314
this->py_recursion_depth = tstate->py_recursion_limit -
tstate->py_recursion_remaining;
+ this->current_executor = tstate->current_executor;
#elif GREENLET_PY312
this->py_recursion_depth = tstate->py_recursion_limit -
tstate->py_recursion_remaining;
this->c_recursion_depth = Py_C_RECURSION_LIMIT -
tstate->c_recursion_remaining;
@@ -213,6 +215,7 @@
#if GREENLET_PY311
#if GREENLET_PY314
tstate->py_recursion_remaining = tstate->py_recursion_limit -
this->py_recursion_depth;
+ tstate->current_executor = this->current_executor;
this->unexpose_frames();
#elif GREENLET_PY312
tstate->py_recursion_remaining = tstate->py_recursion_limit -
this->py_recursion_depth;
@@ -262,6 +265,7 @@
this->_top_frame = nullptr;
#if GREENLET_PY314
this->py_recursion_depth = tstate->py_recursion_limit -
tstate->py_recursion_remaining;
+ this->current_executor = tstate->current_executor;
#elif GREENLET_PY312
this->py_recursion_depth = tstate->py_recursion_limit -
tstate->py_recursion_remaining;
// XXX: TODO: Comment from a reviewer:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/__init__.py
new/greenlet-3.2.4/src/greenlet/__init__.py
--- old/greenlet-3.2.3/src/greenlet/__init__.py 2025-06-05 18:08:17.000000000
+0200
+++ new/greenlet-3.2.4/src/greenlet/__init__.py 2025-08-07 15:13:36.000000000
+0200
@@ -25,7 +25,7 @@
###
# Metadata
###
-__version__ = '3.2.3'
+__version__ = '3.2.4'
from ._greenlet import _C_API # pylint:disable=no-name-in-module
###
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/greenlet_allocator.hpp
new/greenlet-3.2.4/src/greenlet/greenlet_allocator.hpp
--- old/greenlet-3.2.3/src/greenlet/greenlet_allocator.hpp 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/greenlet_allocator.hpp 2025-08-07
15:13:36.000000000 +0200
@@ -5,10 +5,35 @@
#include <Python.h>
#include <memory>
#include "greenlet_compiler_compat.hpp"
+#include "greenlet_cpython_compat.hpp"
namespace greenlet
{
+#if defined(Py_GIL_DISABLED)
+// Python on free threaded builds says this
+//
(https://docs.python.org/3/howto/free-threading-extensions.html#memory-allocation-apis):
+//
+// For thread-safety, the free-threaded build requires that only
+// Python objects are allocated using the object domain, and that all
+// Python object are allocated using that domain.
+//
+// This turns out to be important because the GC implementation on
+// free threaded Python uses internal mimalloc APIs to find allocated
+// objects. If we allocate non-PyObject objects using that API, then
+// Bad Things could happen, including crashes and improper results.
+// So in that case, we revert to standard C++ allocation.
+
+ template <class T>
+ struct PythonAllocator : public std::allocator<T> {
+ // This member is deprecated in C++17 and removed in C++20
+ template< class U >
+ struct rebind {
+ typedef PythonAllocator<U> other;
+ };
+ };
+
+#else
// This allocator is stateless; all instances are identical.
// It can *ONLY* be used when we're sure we're holding the GIL
// (Python's allocators require the GIL).
@@ -58,6 +83,7 @@
};
};
+#endif // allocator type
}
#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/greenlet-3.2.3/src/greenlet/greenlet_cpython_compat.hpp
new/greenlet-3.2.4/src/greenlet/greenlet_cpython_compat.hpp
--- old/greenlet-3.2.3/src/greenlet/greenlet_cpython_compat.hpp 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/greenlet_cpython_compat.hpp 2025-08-07
15:13:36.000000000 +0200
@@ -73,7 +73,9 @@
# define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt)
#endif
-#ifndef _Py_DEC_REFTOTAL
+#ifdef _Py_DEC_REFTOTAL
+# define GREENLET_Py_DEC_REFTOTAL _Py_DEC_REFTOTAL
+#else
/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by:
https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924
@@ -81,12 +83,12 @@
*/
# ifdef Py_REF_DEBUG
# if GREENLET_PY312
-# define _Py_DEC_REFTOTAL
+# define GREENLET_Py_DEC_REFTOTAL
# else
-# define _Py_DEC_REFTOTAL _Py_RefTotal--
+# define GREENLET_Py_DEC_REFTOTAL _Py_RefTotal--
# endif
# else
-# define _Py_DEC_REFTOTAL
+# define GREENLET_Py_DEC_REFTOTAL
# endif
#endif
// Define these flags like Cython does if we're on an old version.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/tests/__init__.py
new/greenlet-3.2.4/src/greenlet/tests/__init__.py
--- old/greenlet-3.2.3/src/greenlet/tests/__init__.py 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/tests/__init__.py 2025-08-07
15:13:36.000000000 +0200
@@ -5,6 +5,7 @@
"""
import os
import sys
+import sysconfig
import unittest
from gc import collect
@@ -36,6 +37,13 @@
RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR
RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX')
+# Is the current interpreter free-threaded?) Note that this
+# isn't the same as whether the GIL is enabled, this is the build-time
+# value. Certain CPython details, like the garbage collector,
+# work very differently on potentially-free-threaded builds than
+# standard builds.
+RUNNING_ON_FREETHREAD_BUILD = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
+
class TestCaseMetaClass(type):
# wrap each test method with
# a) leak checks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/tests/leakcheck.py
new/greenlet-3.2.4/src/greenlet/tests/leakcheck.py
--- old/greenlet-3.2.3/src/greenlet/tests/leakcheck.py 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/tests/leakcheck.py 2025-08-07
15:13:36.000000000 +0200
@@ -136,6 +136,18 @@
# presumably.
IGNORED_TYPES = () #(tuple, dict, types.FrameType, types.TracebackType)
+ # Names of types that should be ignored. Use this when we cannot
+ # or don't want to import the class directly.
+ IGNORED_TYPE_NAMES = (
+ # This appears in Python3.14 with the JIT enabled. It
+ # doesn't seem to be directly exposed to Python; the only way to get
+ # one is to cause code to get jitted and then look for all objects
+ # and find one with this name. But they multiply as code
+ # executes and gets jitted, in ways we don't want to rely on.
+ # So just ignore it.
+ 'uop_executor',
+ )
+
def __init__(self, testcase, function):
self.testcase = testcase
self.function = function
@@ -179,9 +191,14 @@
return False
- if kind in self.ignored_types or kind in self.IGNORED_TYPES:
+ if (
+ kind in self.ignored_types
+ or kind in self.IGNORED_TYPES
+ or kind.__name__ in self.IGNORED_TYPE_NAMES
+ ):
return False
+
return True
def _growth(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/tests/test_greenlet.py
new/greenlet-3.2.4/src/greenlet/tests/test_greenlet.py
--- old/greenlet-3.2.3/src/greenlet/tests/test_greenlet.py 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/tests/test_greenlet.py 2025-08-07
15:13:36.000000000 +0200
@@ -13,6 +13,7 @@
from . import RUNNING_ON_MANYLINUX
from . import PY313
from . import PY314
+from . import RUNNING_ON_FREETHREAD_BUILD
from .leakcheck import fails_leakcheck
@@ -245,7 +246,6 @@
someref.append(g1)
del g1
gc.collect()
-
bg_glet_created_running_and_no_longer_ref_in_bg.set()
fg_ref_released.wait(3)
@@ -261,8 +261,20 @@
self.assertEqual(seen, [])
self.assertEqual(len(someref), 1)
del someref[:]
- gc.collect()
- # g1 is not released immediately because it's from another thread
+ if not RUNNING_ON_FREETHREAD_BUILD:
+ # The free-threaded GC is very different. In 3.14rc1,
+ # the free-threaded GC traverses ``g1``, realizes it is
+ # not referenced from anywhere else IT cares about,
+ # calls ``tp_clear`` and then ``green_dealloc``. This causes
+ # the greenlet to lose its reference to the main greenlet and
thread
+ # in which it was running, which means we can no longer throw an
+ # exception into it, preventing the rest of this test from working.
+ # Standard 3.14 traverses the object but doesn't ``tp_clear`` or
+ # ``green_dealloc`` it.
+ gc.collect()
+ # g1 is not released immediately because it's from another thread;
+ # switching back to that thread will allocate a greenlet and thus
+ # trigger deletion actions.
self.assertEqual(seen, [])
fg_ref_released.set()
bg_should_be_clear.wait(3)
@@ -720,7 +732,18 @@
Greenlet(greenlet_main).switch()
del self.glets
- self.assertEqual(sys.getrefcount(Greenlet), initial_refs)
+ if RUNNING_ON_FREETHREAD_BUILD:
+ # Free-threaded builds make types immortal, which gives us
+ # weird numbers here, and we actually do APPEAR to end
+ # up with one more reference than we started with, at least on
3.14.
+ # If we change the code in green_dealloc to avoid increffing the
type
+ # (which fixed this initial bug), then our leakchecks find other
objects
+ # that have leaked, including a tuple, a dict, and a type. So
that's not the
+ # right solution. Instead we change the test:
+ # XXX: FIXME: Is there a better way?
+ self.assertGreaterEqual(sys.getrefcount(Greenlet), initial_refs)
+ else:
+ self.assertEqual(sys.getrefcount(Greenlet), initial_refs)
@unittest.skipIf(
PY313 and RUNNING_ON_MANYLINUX,
@@ -775,9 +798,12 @@
# non-deterministic. Presumably the memory layouts are different
initial_refs = sys.getrefcount(MyGreenlet)
thread_ready_events = []
- for _ in range(
- initial_refs + 45
- ):
+ thread_count = initial_refs + 45
+ if RUNNING_ON_FREETHREAD_BUILD:
+ # types are immortal, so this is a HUGE number most likely,
+ # and we can't create that many threads.
+ thread_count = 50
+ for _ in range(thread_count):
event = Event()
thread = Thread(target=thread_main, args=(event,))
thread_ready_events.append(event)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/tests/test_leaks.py
new/greenlet-3.2.4/src/greenlet/tests/test_leaks.py
--- old/greenlet-3.2.3/src/greenlet/tests/test_leaks.py 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/tests/test_leaks.py 2025-08-07
15:13:36.000000000 +0200
@@ -15,10 +15,12 @@
import greenlet
from . import TestCase
from . import PY314
+from . import RUNNING_ON_FREETHREAD_BUILD
from .leakcheck import fails_leakcheck
from .leakcheck import ignores_leakcheck
from .leakcheck import RUNNING_ON_MANYLINUX
+
# pylint:disable=protected-access
assert greenlet.GREENLET_USE_GC # Option to disable this was removed in 1.0
@@ -39,6 +41,14 @@
cls.EXTANT_INSTANCES.clear()
+def fails_leakcheck_except_on_free_thraded(func):
+ if RUNNING_ON_FREETHREAD_BUILD:
+ # These all seem to pass on free threading because
+ # of the changes to the garbage collector
+ return func
+ return fails_leakcheck(func)
+
+
class TestLeaks(TestCase):
def test_arg_refs(self):
@@ -265,7 +275,7 @@
finally:
greenlet._greenlet.enable_optional_cleanup(True)
- @fails_leakcheck
+ @fails_leakcheck_except_on_free_thraded
def test_issue251_issue252_need_to_collect_in_background(self):
# Between greenlet 1.1.2 and the next version, this was still
# failing because the leak of the list still exists when we
@@ -286,7 +296,7 @@
# for some reason, but I've never seen it pass on macOS.
self._check_issue251(manually_collect_background=False)
- @fails_leakcheck
+ @fails_leakcheck_except_on_free_thraded
def
test_issue251_issue252_need_to_collect_in_background_cleanup_disabled(self):
self.expect_greenlet_leak = True
greenlet._greenlet.enable_optional_cleanup(False)
@@ -295,7 +305,7 @@
finally:
greenlet._greenlet.enable_optional_cleanup(True)
- @fails_leakcheck
+ @fails_leakcheck_except_on_free_thraded
def test_issue251_issue252_explicit_reference_not_collectable(self):
self._check_issue251(
manually_collect_background=False,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet/tests/test_tracing.py
new/greenlet-3.2.4/src/greenlet/tests/test_tracing.py
--- old/greenlet-3.2.3/src/greenlet/tests/test_tracing.py 2025-06-05
18:08:17.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet/tests/test_tracing.py 2025-08-07
15:13:36.000000000 +0200
@@ -1,5 +1,6 @@
from __future__ import print_function
import sys
+import sysconfig
import greenlet
import unittest
@@ -7,9 +8,16 @@
from . import PY312
#
https://discuss.python.org/t/cpython-3-12-greenlet-and-tracing-profiling-how-to-not-crash-and-get-correct-results/33144/2
-DEBUG_BUILD_PY312 = (
- PY312 and hasattr(sys, 'gettotalrefcount'),
- "Broken on debug builds of Python 3.12"
+# When build variables are available, OPT is the best way of detecting
+# the build with assertions enabled. Otherwise, fallback to detecting PyDEBUG
+# build.
+ASSERTION_BUILD_PY312 = (
+ PY312 and (
+ "-DNDEBUG" not in sysconfig.get_config_var("OPT").split()
+ if sysconfig.get_config_var("OPT") is not None
+ else hasattr(sys, 'gettotalrefcount')
+ ),
+ "Broken on assertion-enabled builds of Python 3.12"
)
class SomeError(Exception):
@@ -198,7 +206,7 @@
self._check_trace_events_from_greenlet_sets_profiler(X(), tracer)
- @unittest.skipIf(*DEBUG_BUILD_PY312)
+ @unittest.skipIf(*ASSERTION_BUILD_PY312)
def test_trace_events_multiple_greenlets_switching(self):
tracer = PythonTracer()
@@ -236,7 +244,7 @@
('c_call', '__exit__'),
])
- @unittest.skipIf(*DEBUG_BUILD_PY312)
+ @unittest.skipIf(*ASSERTION_BUILD_PY312)
def test_trace_events_multiple_greenlets_switching_siblings(self):
# Like the first version, but get both greenlets running first
# as "siblings" and then establish the tracing.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet.egg-info/PKG-INFO
new/greenlet-3.2.4/src/greenlet.egg-info/PKG-INFO
--- old/greenlet-3.2.3/src/greenlet.egg-info/PKG-INFO 2025-06-05
18:08:19.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet.egg-info/PKG-INFO 2025-08-07
15:13:39.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: greenlet
-Version: 3.2.3
+Version: 3.2.4
Summary: Lightweight in-process concurrent programming
Home-page: https://greenlet.readthedocs.io/
Author: Alexey Borzenkov
@@ -38,6 +38,7 @@
Provides-Extra: test
Requires-Dist: objgraph; extra == "test"
Requires-Dist: psutil; extra == "test"
+Requires-Dist: setuptools; extra == "test"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/greenlet-3.2.3/src/greenlet.egg-info/requires.txt
new/greenlet-3.2.4/src/greenlet.egg-info/requires.txt
--- old/greenlet-3.2.3/src/greenlet.egg-info/requires.txt 2025-06-05
18:08:19.000000000 +0200
+++ new/greenlet-3.2.4/src/greenlet.egg-info/requires.txt 2025-08-07
15:13:39.000000000 +0200
@@ -6,3 +6,4 @@
[test]
objgraph
psutil
+setuptools