Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,12 @@ New Features

(Contributed by Eddie Elizondo in :gh:`84436`.)

* Convert the ``PyCurses_API`` C API (``_curses._C_API`` capsule) from a pointer
array to a structure(``PyCurses_C_API``) in pycore_curses.h. ``PyCursesWindow_Type``,
``PyCursesSetupTermCalled``, ``PyCursesInitialised``, ``PyCursesInitialisedColor``
be moved into internal APIs and the public API will be deprecated in 3.14.
(Contributed by Hai Shi in :gh:`87175`).

* :pep:`684`: Add the new :c:func:`Py_NewInterpreterFromConfig`
function and :c:type:`PyInterpreterConfig`, which may be used
to create sub-interpreters with their own GILs.
Expand Down
46 changes: 46 additions & 0 deletions Include/internal/pycore_curses.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef Py_INTERNAL_CURSES_H
#define Py_INTERNAL_CURSES_H

#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
PyTypeObject *window_type;
int (*setup_term_called)(void);
int (*initialized)(void);
int (*initialized_color)(void);
} PyCurses_CAPI;

#ifdef CURSES_MODULE
/* This section is used when compiling _cursesmodule.c */

#else
/* This section is used in modules that use the _cursesmodule API */

static PyCurses_CAPI *PyCurses_C_API;

#undef PyCursesWindow_Type
#undef PyCursesSetupTermCalled
#undef PyCursesInitialised
#undef PyCursesInitialisedColor
#define PyCursesWindow_Type (*PyCurses_C_API->window_type)
#define PyCursesSetupTermCalled {if (!PyCurses_C_API->setup_term_called()) return NULL;}
#define PyCursesInitialised {if (!PyCurses_C_API->initialized()) return NULL;}
#define PyCursesInitialisedColor {if (!PyCurses_C_API->initialized_color()) return NULL;}

#undef import_curses
#define import_curses() \
PyCurses_C_API = PyCapsule_Import(PyCurses_CAPSULE_NAME, 1);

#endif

#ifdef __cplusplus
}
#endif

#endif /* !Py_INTERNAL_CURSES_H */
3 changes: 2 additions & 1 deletion Include/py_curses.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,9 @@
#else
/* This section is used in modules that use the _cursesmodule API */

static void **PyCurses_API;
Py_DEPRECATED(3.14) static void **PyCurses_API;

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Hypothesis tests on Ubuntu

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Cross build Linux

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Cross build Linux

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Ubuntu (installed) / build, install and test

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Lazy imports enabled / Run Tests with lazy_imports=all

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Ubuntu / build and test (ubuntu-26.04)

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Ubuntu / build and test (ubuntu-26.04-arm)

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Ubuntu (free-threading) / build and test (ubuntu-26.04)

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Ubuntu (bolt) / build and test (ubuntu-26.04)

‘PyCurses_API’ defined but not used [-Wunused-variable]

Check warning on line 120 in Include/py_curses.h

View workflow job for this annotation

GitHub Actions / Ubuntu (free-threading) / build and test (ubuntu-26.04-arm)

‘PyCurses_API’ defined but not used [-Wunused-variable]

/* Those macros will be deprecated in 3.14 and moved into internal APIs. */
#define PyCursesWindow_Type (*_PyType_CAST(PyCurses_API[0]))
#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;}
#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;}
Expand Down
5 changes: 3 additions & 2 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_critical_section.h \
$(srcdir)/Include/internal/pycore_crossinterp.h \
$(srcdir)/Include/internal/pycore_crossinterp_data_registry.h \
$(srcdir)/Include/internal/pycore_curses.h \
$(srcdir)/Include/internal/pycore_debug_offsets.h \
$(srcdir)/Include/internal/pycore_descrobject.h \
$(srcdir)/Include/internal/pycore_dict.h \
Expand Down Expand Up @@ -3459,8 +3460,8 @@ Python/thread.o: @THREADHEADERS@ $(srcdir)/Python/condvar.h
MODULE_DEPS_STATIC=Modules/config.c
MODULE_DEPS_SHARED=@MODULE_DEPS_SHARED@

MODULE__CURSES_DEPS=$(srcdir)/Include/py_curses.h
MODULE__CURSES_PANEL_DEPS=$(srcdir)/Include/py_curses.h
MODULE__CURSES_DEPS=$(srcdir)/Include/py_curses.h $(srcdir)/Include/internal/pycore_curses.h
MODULE__CURSES_PANEL_DEPS=$(srcdir)/Include/py_curses.h $(srcdir)/Include/internal/pycore_curses.h
MODULE__DATETIME_DEPS=$(srcdir)/Include/datetime.h
MODULE_CMATH_DEPS=$(srcdir)/Modules/_math.h
MODULE_MATH_DEPS=$(srcdir)/Modules/_math.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Convert the ``PyCurses_API`` C API (``_curses._C_API`` capsule) from a pointer array to a structure(``PyCurses_C_API``) in pycore_curses.h.
``PyCursesWindow_Type``, ``PyCursesSetupTermCalled``, ``PyCursesInitialised``, ``PyCursesInitialisedColor`` be moved into internal APIs and the public API will be deprecated in 3.14.
1 change: 1 addition & 0 deletions Modules/_curses_panel.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ static const char PyCursesVersion[] = "2.1";

#define CURSES_PANEL_MODULE
#include "py_curses.h"
#include "pycore_curses.h"

#if defined(HAVE_NCURSESW_PANEL_H)
# include <ncursesw/panel.h>
Expand Down
29 changes: 16 additions & 13 deletions Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ static const char PyCursesVersion[] = "2.2";

#define CURSES_MODULE
#include "py_curses.h"
#include "pycore_curses.h"

#if defined(HAVE_TERM_H) || defined(__sgi)
/* For termname, longname, putp, tigetflag, tigetnum, tigetstr, tparm
Expand Down Expand Up @@ -9273,26 +9274,28 @@ static void *
curses_capi_new(cursesmodule_state *state)
{
assert(state->window_type != NULL);
void **capi = (void **)PyMem_Calloc(PyCurses_API_pointers, sizeof(void *));
PyCurses_CAPI *capi = PyMem_Malloc(sizeof(PyCurses_CAPI));
if (capi == NULL) {
PyErr_NoMemory();
return NULL;
}
capi[0] = (void *)Py_NewRef(state->window_type);
capi[1] = curses_capi_setupterm_called;
capi[2] = curses_capi_initscr_called;
capi[3] = curses_capi_start_color_called;
/* Initialize the C API struct */
capi->window_type = (PyTypeObject *)Py_NewRef(state->window_type);
capi->setup_term_called = curses_capi_setupterm_called;
capi->initialized = curses_capi_initscr_called;
capi->initialized_color = curses_capi_start_color_called;
return (void *)capi;
}

static void
curses_capi_free(void *capi)
{
assert(capi != NULL);
void **capi_ptr = (void **)capi;
// In free-threaded builds, capi_ptr[0] may have been already cleared
// by curses_capi_capsule_destructor(), hence the use of Py_XDECREF().
Py_XDECREF(capi_ptr[0]); // decref curses window type
PyCurses_CAPI *capi_ptr = (PyCurses_CAPI *)capi;
// In free-threaded builds, capi_ptr->window_type may have been already
// cleared by curses_capi_capsule_destructor(), hence the use of
// Py_XDECREF().
Py_XDECREF(capi_ptr->window_type); // decref curses window type
PyMem_Free(capi_ptr);
}

Expand All @@ -9308,18 +9311,18 @@ curses_capi_capsule_destructor(PyObject *op)
static int
curses_capi_capsule_traverse(PyObject *op, visitproc visit, void *arg)
{
void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
PyCurses_CAPI *capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
assert(capi_ptr != NULL);
Py_VISIT(capi_ptr[0]); // visit curses window type
Py_VISIT(capi_ptr->window_type); // visit curses window type
return 0;
}

static int
curses_capi_capsule_clear(PyObject *op)
{
void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
PyCurses_CAPI *capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME);
assert(capi_ptr != NULL);
Py_CLEAR(capi_ptr[0]); // clear curses window type
Py_CLEAR(capi_ptr->window_type); // clear curses window type
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions PCbuild/pythoncore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
<ClInclude Include="..\Include\internal\pycore_critical_section.h" />
<ClInclude Include="..\Include\internal\pycore_crossinterp.h" />
<ClInclude Include="..\Include\internal\pycore_crossinterp_data_registry.h" />
<ClInclude Include="..\Include\internal\pycore_curses.h" />
<ClInclude Include="..\Include\internal\pycore_debug_offsets.h" />
<ClInclude Include="..\Include\internal\pycore_descrobject.h" />
<ClInclude Include="..\Include\internal\pycore_dict.h" />
Expand Down
3 changes: 3 additions & 0 deletions PCbuild/pythoncore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,9 @@
<ClInclude Include="..\Include\internal\pycore_crossinterp_data_registry.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_curses.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_debug_offsets.h">
<Filter>Include\internal</Filter>
</ClInclude>
Expand Down
1 change: 1 addition & 0 deletions Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ Modules/_xxtestfuzz/fuzzer.c LLVMFuzzerTestOneInput ELEMENTTREE_PARSEWHOLE_INITI
# XXX Fix the analyzer.

## forward/extern references
Include/internal/pycore_curses.h - PyCurses_C_API -
Include/internal/pycore_importdl.h - _PyImport_DynLoadFiletab -
Include/py_curses.h - PyCurses_API -
Include/pydecimal.h - _decimal_api -
Expand Down
Loading