Skip to content

Commit 1db0fc6

Browse files
authored
Merge pull request #327 from mdboom/python-312
Fix #323: Support Python 3.12
2 parents 1fbcc47 + 1c7bfee commit 1db0fc6

File tree

5 files changed

+62
-8
lines changed

5 files changed

+62
-8
lines changed

.github/workflows/tests.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ jobs:
2525
runs-on: ${{ matrix.os }}
2626
strategy:
2727
matrix:
28-
python-version: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11"]
28+
python-version: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12-dev"]
2929
# Jan 2023: We have pinned back from ubuntu-latest (which is
3030
# now ubuntu 22.04) because older Python versions like
3131
# 3.5, 3.6 and presumably 2.7 are not available in it.
3232
os: [ubuntu-20.04, macos-latest]
33+
exclude:
34+
- os: macos-latest
35+
python-version: 3.12-dev
3336
steps:
3437
- uses: actions/checkout@v3
3538
- name: Set up Python
@@ -77,6 +80,7 @@ jobs:
7780
path: dist/*whl
7881
- name: Test
7982
run: |
83+
python -VV
8084
python -c 'import greenlet._greenlet as G; assert G.GREENLET_USE_STANDARD_THREADING'
8185
python -m unittest discover -v greenlet.tests
8286
- name: Doctest

CHANGES.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
compilers for some time. See `PR 347
1919
<https://github.com/python-greenlet/greenlet/pull/347>`_ from Khem
2020
Raj.
21+
- Add initial support for Python 3.12. See `issue
22+
<https://github.com/python-greenlet/greenlet/issues/323>`_ and `PR
23+
<https://github.com/python-greenlet/greenlet/pull/327>`_; thanks go
24+
to (at least) Michael Droettboom, Andreas Motl, Thomas A Caswell,
25+
raphaelauv, Hugo van Kemenade, Mark Shannon, and Petr Viktorin.
2126

2227

2328
2.0.2 (2023-01-28)

src/greenlet/greenlet.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3095,7 +3095,12 @@ static PyObject*
30953095
mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module))
30963096
{
30973097
PyThreadState* tstate = PyThreadState_GET();
3098+
3099+
#if GREENLET_PY312
3100+
return PyLong_FromLong(tstate->trash.delete_nesting);
3101+
#else
30983102
return PyLong_FromLong(tstate->trash_delete_nesting);
3103+
#endif
30993104
}
31003105

31013106
static PyMethodDef GreenMethods[] = {

src/greenlet/greenlet_cpython_compat.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ We have to save and restore this as well.
4848
# define GREENLET_USE_CFRAME 0
4949
#endif
5050

51+
#if PY_VERSION_HEX >= 0x30C0000
52+
# define GREENLET_PY312 1
53+
#else
54+
# define GREENLET_PY312 0
55+
#endif
56+
5157
#if PY_VERSION_HEX >= 0x30B00A4
5258
/*
5359
Greenlet won't compile on anything older than Python 3.11 alpha 4 (see

src/greenlet/greenlet_greenlet.hpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,12 @@ namespace greenlet
143143
_PyCFrame* cframe;
144144
int use_tracing;
145145
#endif
146+
#if GREENLET_PY312
147+
int py_recursion_depth;
148+
int c_recursion_depth;
149+
#else
146150
int recursion_depth;
151+
#endif
147152
int trash_delete_nesting;
148153
#if GREENLET_PY311
149154
_PyInterpreterFrame* current_frame;
@@ -748,7 +753,12 @@ PythonState::PythonState()
748753
,cframe(nullptr)
749754
,use_tracing(0)
750755
#endif
756+
#if GREENLET_PY312
757+
,py_recursion_depth(0)
758+
,c_recursion_depth(0)
759+
#else
751760
,recursion_depth(0)
761+
#endif
752762
,trash_delete_nesting(0)
753763
#if GREENLET_PY311
754764
,current_frame(nullptr)
@@ -828,24 +838,34 @@ void PythonState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT
828838
the switch, use `will_switch_from`.
829839
*/
830840
this->cframe = tstate->cframe;
841+
#if !GREENLET_PY312
831842
this->use_tracing = tstate->cframe->use_tracing;
843+
#endif
832844
#endif
833845
#if GREENLET_PY311
846+
#if GREENLET_PY312
847+
this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
848+
this->c_recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining;
849+
#else
834850
this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
851+
#endif
835852
this->current_frame = tstate->cframe->current_frame;
836853
this->datastack_chunk = tstate->datastack_chunk;
837854
this->datastack_top = tstate->datastack_top;
838855
this->datastack_limit = tstate->datastack_limit;
839856
PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate);
840857
Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new reference.
841858
this->_top_frame.steal(frame);
859+
#if GREENLET_PY312
860+
this->trash_delete_nesting = tstate->trash.delete_nesting;
861+
#else
862+
this->trash_delete_nesting = tstate->trash_delete_nesting;
863+
#endif
842864
#else
843865
this->recursion_depth = tstate->recursion_depth;
844866
this->_top_frame.steal(tstate->frame);
845-
#endif
846-
847-
// All versions of Python.
848867
this->trash_delete_nesting = tstate->trash_delete_nesting;
868+
#endif
849869
}
850870

851871
void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT
@@ -864,26 +884,37 @@ void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT
864884
root_cframe here. See note above about why we can't
865885
just copy this from ``origin->cframe->use_tracing``.
866886
*/
887+
#if !GREENLET_PY312
867888
tstate->cframe->use_tracing = this->use_tracing;
889+
#endif
868890
#endif
869891
#if GREENLET_PY311
892+
#if GREENLET_PY312
893+
tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth;
894+
tstate->c_recursion_remaining = C_RECURSION_LIMIT - this->c_recursion_depth;
895+
#else
870896
tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth;
897+
#endif
871898
tstate->cframe->current_frame = this->current_frame;
872899
tstate->datastack_chunk = this->datastack_chunk;
873900
tstate->datastack_top = this->datastack_top;
874901
tstate->datastack_limit = this->datastack_limit;
875902
this->_top_frame.relinquish_ownership();
903+
#if GREENLET_PY312
904+
tstate->trash.delete_nesting = this->trash_delete_nesting;
905+
#else
906+
tstate->trash_delete_nesting = this->trash_delete_nesting;
907+
#endif
876908
#else
877909
tstate->frame = this->_top_frame.relinquish_ownership();
878910
tstate->recursion_depth = this->recursion_depth;
879-
#endif
880-
// All versions of Python.
881911
tstate->trash_delete_nesting = this->trash_delete_nesting;
912+
#endif
882913
}
883914

884915
void PythonState::will_switch_from(PyThreadState *const origin_tstate) G_NOEXCEPT
885916
{
886-
#if GREENLET_USE_CFRAME
917+
#if GREENLET_USE_CFRAME && !GREENLET_PY312
887918
// The weird thing is, we don't actually save this for an
888919
// effect on the current greenlet, it's saved for an
889920
// effect on the target greenlet. That is, we want
@@ -895,7 +926,10 @@ void PythonState::will_switch_from(PyThreadState *const origin_tstate) G_NOEXCEP
895926
void PythonState::set_initial_state(const PyThreadState* const tstate) G_NOEXCEPT
896927
{
897928
this->_top_frame = nullptr;
898-
#if GREENLET_PY311
929+
#if GREENLET_PY312
930+
this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
931+
this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
932+
#elif GREENLET_PY311
899933
this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
900934
#else
901935
this->recursion_depth = tstate->recursion_depth;

0 commit comments

Comments
 (0)